0% found this document useful (0 votes)
92 views20 pages

Tower of Hanoi Recursion Explained

The document discusses the Tower of Hanoi puzzle and provides pseudocode to recursively solve it. It explains that the puzzle involves moving disks of different sizes between three towers according to rules of only moving one disk at a time and not placing a larger disk on top of a smaller one. The recursive solution works by breaking the problem down into smaller subproblems of moving all but the largest disk, moving the largest disk, and then moving the remaining disks. It also provides Java code examples to both print out the moves and to actually maintain the state of the towers using stacks.

Uploaded by

jahanzeb
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
92 views20 pages

Tower of Hanoi Recursion Explained

The document discusses the Tower of Hanoi puzzle and provides pseudocode to recursively solve it. It explains that the puzzle involves moving disks of different sizes between three towers according to rules of only moving one disk at a time and not placing a larger disk on top of a smaller one. The recursive solution works by breaking the problem down into smaller subproblems of moving all but the largest disk, moving the largest disk, and then moving the remaining disks. It also provides Java code examples to both print out the moves and to actually maintain the state of the towers using stacks.

Uploaded by

jahanzeb
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

1/15/2016

AlgorithmsandDataStructuresI

Module9:Recursion,PartII
Supplementalmaterial
TheTowerofHanoi

IntheTowerofHanoipuzzle:
Therearethreestacks(towers),numbered0,1,2.

ThereareNdisksnumbered0,...,N1.
=>0isthesmallest.
Initially,thedisksareplacedintower0,intheorderlargesttosmallest.
=>Smallestontop.
Goal:tomovethediskstotower1usingonlylegalmoves.
What'salegalmove?
Youcanmoveonlyadiskatthetopofatower.
Youcanmoveonlyonediskatatime.
Youcannotplaceadiskontopofasmallerone.

Wewillsolvetheproblemusing(ofcourse)recursion:
Therearethreekeystepsintherecursion:

Step1:movedisks0,...,N2fromtower0totower2
[Link]

1/20

1/15/2016

AlgorithmsandDataStructuresI

=>Subproblemofsmallersize.

Step2:movediskN1fromtower0totower1.

Step3:movedisks0,...,N2fromtower2totower1.
=>Subproblemofsmallersize.

Inpseudocode(withoutbasecase):
AlgorithmtowerOfHanoi(n,i,j)
Input:Disksnumbered0,...,naretobemovedfromtoweritotowerj
1.//...basecase...
//Firstfindthethirdtower,otherthaniandj:
2.k=otherTower(i,j)
//Step1:movedisks0,..,n1fromitok
[Link](n1,i,k)
//Step2:movedisk#nfromitoj
[Link](n,i,j)
//Step3:movedisks0,...,n1fromktoj
[Link](n1,k,j)

Thebasecase:moveasingledisk

[Link]

2/20

1/15/2016

AlgorithmsandDataStructuresI

Here'stheprogram:(sourcefile)
publicclassTowerOfHanoi{
publicstaticvoidmain(String[]argv)
{
//A3diskpuzzle:
[Link]("3Disksolution:");

solveHanoi(2,0,1);
//A4diskpuzzle:
[Link]("4Disksolution:");

solveHanoi(3,0,1);
}
staticvoidsolveHanoi(intn,inti,intj)
{

//Bottomout.

if(n==0){
//Thesmallestdisk.

move(0,i,j);

return;

intk=other(i,j);
solveHanoi(n1,i,k);//Step1.
move(n,i,j);//Step2.
solveHanoi(n1,k,j);//Step3.

staticvoidmove(intn,inti,intj)
{
//Fornow,we'llmerelyprintoutthemove.
[Link]("=>Movedisk#"+n+"fromtower"+i+"totower"+j);
}
staticintother(inti,intj)
{
//Giventwotowers,returnthethird.
if((i==0)&&(j==1)){
return2;
}
elseif((i==1)&&(j==0)){
return2;
}
elseif((i==1)&&(j==2)){
return0;
}
elseif((i==2)&&(j==1)){
return0;
}
elseif((i==0)&&(j==2)){
return1;
}
elseif((i==2)&&(j==0)){
return1;
}
//Weshouldn'treachhere.
return1;
}
}

Note:
Theaboveprogrammerelyprintsoutthemovesneeded
=>Wedon'tactuallymaintainthestateofeachtower.

[Link]

3/20

1/15/2016

AlgorithmsandDataStructuresI

Next,supposewewanttomaintainthestateofeachtower:
Theidealdatastructureisastack.
We'lluseonestackforeachtower.
Here'stheprogram:(sourcefile)
[Link].*;
publicclassTowerOfHanoi2{
//towers[0],towers[1]andtowers[2]arethethreestacks.
staticStack<Integer>[]towers;
publicstaticvoidmain(String[]argv)
{
//A3diskpuzzle:
[Link]("3Disksolution:");

solveHanoi(2,0,1);
//A4diskpuzzle:
[Link]("4Disksolution:");

solveHanoi(3,0,1);
}
staticvoidsolveHanoi(intn,inti,intj)
{
//Createthethreestacks.

towers=newStack[3];

for(intk=0;k<3;k++){

towers[k]=newStack<Integer>();

}
//Putdisks0,...,nonstack0.

for(intk=n;k>=0;k){

towers[0].add(k);

}
//Printtheinitialstack.

printTowers();
//[Link]:thisisthemethodbelow.

solveHanoiRecursive(n,i,j);
}

staticvoidsolveHanoiRecursive(intn,inti,intj)
{

//Bottomout.

if(n==0){

move(0,i,j);

return;

intk=other(i,j);

solveHanoiRecursive(n1,i,k);//Step1.

move(n,i,j);//Step2.

solveHanoiRecursive(n1,k,j);//Step3.
}
staticvoidmove(intn,inti,intj)
{
//Pulloutthetopdiskonstacki.

inttopVal=towers[i].pop();
//Putitonstackj.

towers[j].push(topVal);
//Printstatus.
[Link]("Towersaftermoving"+n+"fromtower"+i+"totower"+j);

printTowers();
}
[Link]

4/20

1/15/2016

AlgorithmsandDataStructuresI

staticintother(inti,intj)
{
//...
}
staticvoidprintTowers()
{

for(inti=0;i<[Link];i++){

[Link]("Tower"+i+":");

if(!towers[i].isEmpty()){

for(IntegerI:towers[i]){

[Link](""+I);

[Link]();

}
}
}

Note:
Sinceweneededtocreatethestacksaheadoftime,wemovedtherecursivepartofthecodeintoanewrecursive
methodsolveHanoiRecursive().
Toremoveadiskfromthetopofatower,wepop()fromthattower(stack):
//Pulloutthetopdiskonstacki.

inttopVal=towers[i].pop();

Toplaceadiskontopofatower,wepush()it:
//Putitonstackj.

towers[j].push(topVal);

NoticehowprintTowers()usesthe"collection"versionoftheforloop:

if(!towers[i].isEmpty()){
//Newtypeofforloop:

for(IntegerI:towers[i]){

[Link](""+I);

Astrangecompilationmessage:
Incompilingtheaboveprogram(withaJava1.5compiler),wegetawarning(notanerror):
Note:[Link].
Note:RecompilewithXlint:uncheckedfordetails.

Thisallowsyoutocontinuewithexecution.
Youcan,asitsuggests,recompilewiththeXlint:uncheckedoption:
javacXlint:[Link]

Whatyouseeasaresult:
[Link][Link]warning:[unchecked]uncheckedconversion
found:[Link][]
required:[Link][]
towers=newStack[3];
^

Thecompilerdidnotlikethestatement:
[Link]

5/20

1/15/2016

AlgorithmsandDataStructuresI

towers=newStack[3];

So,shouldthisinsteadhavebeen
towers=newStack<Integer>[3];

asonemightintuitivelyexpect?
Unfortunately,thatresultsinacompilationerror.
ThereasonisquiteesotericandhastodowiththegorydetailsofgenerictypesarehandledinJava.
Essentially,itboilsdowntothis:adeclarationlike
towers=newStack<Integer>[3];

isunsafebecauseonecanassignnonIntegerstackstotowers,whichiswhythecompilerdoesn'tallowit.
Thus,weareleftwithusingtheslightlylessunsafe
towers=newStack[3];

whichthecompilerallowsbutwarnsagainst.
GenerictypesinJavaconstitutealargeandsomewhatadvancedtopic,toocomplicatedforthiscourse.

Anapplication:diskbackupschedules
Supposewehavefourdisks(A,B,CandD)onwhichwewishtoperformbackupseachday.
=>Thisisadifferentmeaningofdisk(harddrive,removablemedia)
Eachdayweneedtochooseadiskonwhichtobackup
=>Thebackupschedule.
Oneoptionistogoroundrobin
Day0usediskA
Day1usediskB
Day2usediskC
Day3usediskD
Day4usediskA
Day5usediskB
...
(andsoon)

Withthissystem,wecanonlygobackatmostfourdays.
Wearenotabletoretrievethestateofthesystemfrom,say,6daysago.
Anotherapproach:staggerthedisks:
Day0usediskA
Day1usediskB
Day2usediskA
Day3usediskC
Day4usediskA
Day5usediskB
Day6usediskA
Day7usediskD
Day8usediskA
...
(andsoon)

Withthisapproach,we'dhaveadistributionlike
DiskA1or2daysbefore
DiskBatmost4daysbefore
DiskCatmost8daysbefore
DiskDatmost16daysbefore

[Link]

6/20

1/15/2016

AlgorithmsandDataStructuresI

Thisdistributionallowsadeeperreachintothepast.
ThesequenceaboveisexactlytheTowerofHanoimovesequencefordisksnumberedA,B,CandD.

Recursion:areview

First,let'sreviewasimpleexamplefromModule4:
Recalltherecursivecomputationofpower:
//Computeab
staticintpower(inta,intb)
{
//Bottomout:
if(b==0){
return1;
}
//Recursion:
return(a*power(a,b1));
}

What'simportant:
Wemusttestforthebottomoutcasebeforerecursing.
Thebottomoutcaseteststhevalue(orvalues)oftheparameter(orparameters)thatchangesinthe
recursion.
=>Thesearetheparametersthatcontroltherecursion.
Therecursivecallsmustchange(usuallydecrease)theparametersthatcontroltherecursion.
=>Above,thereisonlyonerecursivecall,butTowerofHanoihastwo.
Howrecursionworks:
Eachmethodcallcreatesanactivationrecordonthesystemstack.
Theactivationrecordconsistsofspaceallocatedfortheparticularparametersandlocalvariablesforthat
methodcall.
Thus,arecursivecallresultsinanewactivationrecordforeachsuchrecursivecall.
=>Thisiswhyeachexecutionofthemethodretainsitsownparametersandlocalvariables.
Theactivationrecordalsoknowsthatwhenexecutionofamethodcallcompletes,executionreturnstothe
callingmethodjustafterthecalledmethodwascalled.
Forrecursionit'snodifferentexceptthatit'sthesamecodeinvolvedinallmethodcalls.
Thebestwaytounderstandrecursioninitiallyistodrawthestackpictureandworkthroughanexample.

Let'snowreviewanotherexamplefromModule4:
Thisisthepermutationseatingexamplewhereweprintthearrangement:
//Theparameterstothismethodare:
//numSpacestotalnumberofremainingseatsavailable
//numRemainingtotalnumberofpeoplelefttoseat
//seatsanarraywhereseats[i]==0ifseatisavailable
//personwhichpersonweneedtoseat
staticvoidprintPermutations(intnumSpaces,intnumRemaining,int[]seats,intperson)
{
//Bottomoutcase.

if(numRemaining==0){

//Print.

[Link]([Link](seats));

return;

}
[Link]

7/20

1/15/2016

AlgorithmsandDataStructuresI

//Otherwise,nonbasecase:lookforanemptyspotfor"person"
for(inti=0;i<[Link];i++){
if(seats[i]==0){

//Emptyspot.
seats[i]=person;

//Recursivelyassignremaining,startingwithperson+1

printPermutations(numSpaces1,numRemaining1,seats,person+1);
//Important:weneedtoundotheseatingforothertrials.

seats[i]=0;

}//endfor
}

What'ssimilaraboutthisrecursivemethod:
Theparameterthatcontrolsrecursionis:numSpaces
=>Thisiswhatwecheckinthebottomoutcase.
Otherparameterspassalonginformation:personandseats.
What'sdifferent(fromthepower()example):
Whenwefillintheseatsarray,weundothisassignmentaftertherecursivecall:
//Makesomechangetoaparameter:

seats[i]=person;
//Recurse:

printPermutations(numSpaces1,numRemaining1,seats,person+1);
//Undothechange(restoretheoriginal)forfuturerecursions:

seats[i]=0;

Twotypesofrecursion:
Recursionwhereyoudon'tundochanges.
=>Sometimesthisiscalledtailrecursion.
Recursionwhereyouneedtoundochangessothatyoucanproperlyexploreallpossibilities
=>Sometimesthisiscalledrecursionwithbacktracking.
Manyexamplesoftailrecursioncaneasilybewrittennonrecursively(usingiteration)
=>Formanyoftheseexamples(power,factorial,fibonacci),it'sbettertouseiteration.
However,whenthere'sbacktracking,itcanbeverydifficulttoavoidrecursion.

Mazeconstructionandtraversal:a(long)exampleofrecursionwithbacktracking

Wewillnowexamineamazeapplicationindetailtoillustraterecursionwithbacktracking:
First,wewilluserecursiontocreateamazelikethis:

[Link]

8/20

1/15/2016

AlgorithmsandDataStructuresI

Then,wewilluserecursiontosolvesuchamaze(byfindingapathfromagivenstartcell(e.g.,thetopleft)toa
givenendcell(e.g.,thebottomright):

WewillputawholebunchofusefulcodeinaclasscalledMazeandinsteadfocusonusingthatclassthroughits
methods.
[Link]

9/20

1/15/2016

AlgorithmsandDataStructuresI

We'llusethiscellnumberingconvention:
Rowsstartnumberingat0,andincreasedownwards.
Columnsstartat0andincreaserightwards.
Thus,thetopleftcellis(0,0).Theonetoitsrightis(0,1)andtheonedirectlybelowis(1,0).

Tostartwith,let'sexaminethemethodsintheclassMaze:
Theconstructor:wecreateaninstancebyspecifyingthenumberofrowsandcolumns:
Mazemaze=newMaze(5,5);

Ourexampleswillusesquaremazes.
display():callthismethodtodisplaythemaze:
Mazemaze=newMaze(5,5);
//BringuptheGUI:
[Link]();

breakWall():

Initially,[Link],wewill"breakwalls"
betweenneighboringcells.
Forexample,wecanbreakthewallbetweencells(3,4)and(2,4)asfollows:
Mazemaze=newMaze(5,5);
//NotetheuseoftheCoordclass:
Coordc1=newCoord(3,4);
Coordc2=newCoord(2,4);
[Link](c1,c2);
[Link]();

Or,alternatively,withshortercode:
Mazemaze=newMaze(5,5);
//Createaninstancedirectlyinthemethodargumentlist:
[Link](newCoord(3,4),newCoord(2,4));
[Link]();

TheCoordclasslookslikethis:
publicclassCoord{
publicintrow=1,col=1;
publicCoord(intr,intc)
{
row=r;
col=c;
}

publicStringtoString()
{
return"["+row+","+col+"]";
}

Thus,toaccessthestoredcoordinates:
Coordc=newCoord(3,4);
[Link]("Row="+[Link]+"Col="+[Link]);
[Link]

10/20

1/15/2016

AlgorithmsandDataStructuresI

//Or,toprintbothusingtoString():
[Link](c);

Anumberofmethods(intheclassMaze)allowustomarkandunmarkcellsasvisited:
markVisited(Coordc):markcellcasvisited.
markUnVisited(Coordc):markcellcasnotvisited.
markAllUnvisited():markallcellsasunvisited.
isVisited(Coordc):seewhethercellchasbeenvisited.
Anumberofmethodsrelatedtofetchingalist(array)ofacell'sneighbors:
Coord[]getUnvisitedClosedNeighbors(Coordc):getcellc'sneighborsthatareclosedofffromc(there's
awallbetween)andhaven'tbeenvisitedyet.
Coord[]getClosedNeighbors(Coordc):getneighborsofcthatshareawall(unbroken)withcwhether
visitedornot.
Coord[]getUnvisitedOpenNeighbors(Coordc):getthoseneighborsofcforwhichwecanwalkthrough
totheneighbor(nowall)andwhichhaven'tbeenvisited.
EachofthesemethodsreturnanarrayofCoordinstances.
Afewadditionalusefulmethods:
copy():makeafullcopyofthemaze,asin:
Mazem=newMaze(5,5);
//...dostuff:breakwallsetc...
Mazem2=[Link]();
//[Link]'taffectm2.

setSolutionPath(LinkedList<Coord>solutionPath):wewillcallthismethodoncewehaveconstructed

asolution.

We'llnowwriteourfirstattempt:
Wewilltrytogenerateamazepathofagivenpathlength.
Thekeyidea:
Algorithm:recursiveGenerate(Coordc)
[Link]
[Link]
//Otherwise...
3.c'=Pickarandomneighborofcellc
[Link](c')

Here'stheprogram:(sourcefile)
publicclassMazeMaker{
//Thesevariableswillbeusedacrossmethods:
staticintdesiredPathLength;
staticMazemaze;
publicstaticvoidmain(String[]argv)
{
generateMaze(5,5);
}
publicstaticvoidgenerateMaze(intnumRows,intnumCols)
{
maze=newMaze(numRows,numCols);
//Wewanttogenerateapathofthislength:

desiredPathLength=numRows*numCols;

//Initially,we'llstartwiththetopleftcellandmarkthatasvisited.
Coordstart=newCoord(0,0);

[Link](start);
[Link]

11/20

1/15/2016

AlgorithmsandDataStructuresI

//Generatethemazepathrecursively.

booleanfound=recursiveGenerate(start,1);
if(!found){
[Link]("Couldnotcreatethewholemaze");
}
[Link]();
}
staticbooleanrecursiveGenerate(Coordc,intpathLength)
{
//Bottomoutcondition1:

if(pathLength==desiredPathLength){

//[Link]'vecreateamazepathofthedesiredlength.

returntrue;

}
//Bottomoutcondition2:seeifthere'saneighbortovisit.

Coord[]validNeighbors=[Link](c);

if((validNeighbors==null)||([Link]==0)){
//There'[Link].

returnfalse;

}
//Otherwise,pickarandomneighborandproceed.
inti=[Link](0,validNeighbors.length1);
//Breakthewallandmarktheneighborasvisited.
[Link](c,validNeighbors[i]);
[Link](validNeighbors[i]);

//Recurse.
returnrecursiveGenerate(validNeighbors[i],pathLength+1);
}
}

Nextattempt:
Simpletailrecursioncangetstuck.
=>Weneedawayto"undo"pathsandtrydifferentneighbors.
Wewillpickaneighbortoexplorerecursively
=>Ifthatdoesn'tworkout,we'lltryanother.
Here'stheprogram:(sourcefile)
publicclassMazeMaker2{
staticintdesiredPathLength;
staticMazemaze;
publicstaticvoidmain(String[]argv)
{
generateMaze(5,5);
}
publicstaticvoidgenerateMaze(intnumRows,intnumCols)
{
maze=newMaze(numRows,numCols);

desiredPathLength=numRows*numCols;

//Initially,we'llstartwiththetopleftcell.
Coordstart=newCoord(0,0);

[Link](start);
//Generatethemazepathrecursively.
[Link]

12/20

1/15/2016

AlgorithmsandDataStructuresI

booleanfound=recursiveGenerate(start,1);

if(!found){
[Link]("Couldnotcreatethewholemaze");
}
[Link]();
}
staticbooleanrecursiveGenerate(Coordc,intpathLength)
{
//Bottomoutcondition1:

if(pathLength==desiredPathLength){

returntrue;

}
//Bottomoutcondition1:seeifwe'restuck.

Coord[]validNeighbors=[Link](c);

if((validNeighbors==null)||([Link]==0)){

returnfalse;

//Otherwise,wehavesomeneighborstoexplore.
//Permutethedirectionsrandomly.
permute(validNeighbors);

for(inti=0;i<[Link];i++){

//Tryneighbori.
[Link](c,validNeighbors[i]);
[Link](validNeighbors[i]);

booleanok=recursiveGenerate(validNeighbors[i],pathLength+1);

if(ok){
//Ifneighboriworkedout,great.

returntrue;

//Otherwise,undoassignmenttoi.
[Link](c,validNeighbors[i]);
[Link](validNeighbors[i]);

}//endfor

//Couldn'tmakeitwork.
returnfalse;

staticvoidpermute(Coord[]coords)
{

for(inti=0;i<[Link];i++){

//Findarandomelementtoplaceintoithplace.

intk=(int)[Link](i,coords.length1);

Coordtemp=coords[i];

coords[i]=coords[k];

coords[k]=temp;

}
}
}

Note:
Thekeyideaistotryasmanyneighborsasneeded:
Algorithm:recursiveGenerate(Coordc)
[Link]
[Link]
[Link]
//Otherwise...
[Link]'ofc
[Link]=recursiveGenerate(c')
[Link]
[Link]

13/20

1/15/2016

AlgorithmsandDataStructuresI

[Link]
[Link]
[Link]
//Wereachhereonlyifeveryneighbordidnotworkout.
[Link]

Notehowweundoabrokenwall:

for(inti=0;i<[Link];i++){
//Tryneighbori.
[Link](c,validNeighbors[i]);
[Link](validNeighbors[i]);

//...recursionhere...

//Toundo:repairthewallandmarkasUNvisited.
[Link](c,validNeighbors[i]);
[Link](validNeighbors[i]);
}//endfor

Amazewithchoices:
Theabovemazepathhasnochoices
=>There'sonlyonewayfromthetoplefttotheendofthepath.
Wewillbuilduponthistocreateamazewithchoices
=>Aftergeneratingthelongpath,we'llbreaksomerandomwalls.
Here'stheprogram:(sourcefile)
publicclassMazeMaker3{
//...variables...
publicstaticvoidmain(String[]argv)
{
generateMaze(5,5);
}
publicstaticvoidgenerateMaze(intnumRows,intnumCols)
{
//...createandgeneratesinglepathmaze...
//Breakafewmorewalls,randomly.
breakRandomWalls(maze,10);
[Link]();
}
staticbooleanrecursiveGenerate(Coordc,intpathLength)
{
//...sameasbefore...
}

staticvoidbreakRandomWalls(Mazemaze,intnumWalls)
{

for(intk=0;k<numWalls;k++){
//Createrandomcoordinates,i.e.,identifyarandomcell.

intx=[Link](0,maze.numRows1);

inty=[Link](0,maze.numCols1);

Coordc=newCoord(x,y);
//Getitsneighborsthatareseparatedbyawall.

Coord[]validNeighbors=[Link](c);

if(validNeighbors!=null){
[Link]

14/20

1/15/2016

AlgorithmsandDataStructuresI

//Pickoneandbreakthewall.
intm=[Link](0,validNeighbors.length1);

[Link](c,validNeighbors[m]);

}
}
}

Let'sturnourattentiontosolvingthemaze:
We'llfirsttryasimpleidea:
Algorithm:recursivelyFindPath(Coordc)
[Link]
[Link]
[Link]
4.//Otherwisesearchfurther...
5.c'=pickarandom"open"neighbor
[Link]'isnull
//Stuck:couldn'tfindapath.
[Link]
[Link]
[Link](c')

Here'stheprogram:(sourcefile)
[Link].*;
publicclassMazeMaker4{
staticintdesiredPathLength;
staticMazemaze;
publicstaticvoidmain(String[]argv)
{
Mazemaze=generateMaze(5,5);

if(maze!=null){
//Wewillseekapathfromthetoplefttothebottomrightcorner.

Coordstart=newCoord(0,0);

Coordend=newCoord(4,4);

solveMaze(maze,start,end);

[Link]();

else{

[Link]("Mazecreationdidnotwork");

}
}
//Apathisalistofcells,i.e.,alistofCoordinstances.
staticLinkedList<Coord>solutionPath;
staticvoidsolveMaze(Mazemaze,Coordstart,Coordend)
{
//We'[Link]:

[Link]();
//Markthestartcellasvisited.

[Link](start);
//Createthelist.

solutionPath=newLinkedList<Coord>();
//Recursivelyfindthepathandfillincoord'sintothelist.

recursivelyFindPath(maze,start,end);
//PassthepathintotheGUI.

[Link](solutionPath);
[Link]

15/20

1/15/2016

AlgorithmsandDataStructuresI

}
staticbooleanrecursivelyFindPath(Mazemaze,Coordc,Coordend)
{
//Firstaddthecurrentcellintothepath.

[Link](c);
//Ifwe'vereachedtheend,we'redone.

if(([Link]==[Link])&&([Link]==[Link])){

returntrue;

}
//Otherwise,let'sfindaneighbortoexplore.

Coord[]validNeighbors=[Link](c);

if(validNeighbors==null){
//Iftherearen'tany,we'redone,butcouldn'tfindapath.

returnfalse;

//Takethefirstoneandexplorefromthere.
[Link](validNeighbors[0]);

returnrecursivelyFindPath(maze,validNeighbors[0],end);

//...Mazegenerationcode...sameasbefore...
}

Asolutionthatworks:
Whenexploringaneighbor,weneedawaytoundo(backtrack)ifitdoesn'tleadtoasolution.
Theideaistotryallpossibleneighbors,asmanyasneeded:
Algorithm:recursivelyFindPath(Coordc)
[Link]
[Link]
[Link]
4.//Otherwisesearchfurther...
[Link]"open"neighborc'
[Link]=recursivelyFindPath(c')
[Link]
[Link]'topath
[Link]
[Link]
[Link]
[Link]

Here'stheprogram:(sourcefile)
[Link].*;
publicclassMazeMaker5{
//...variables...sameasbefore(forgeneration)...
publicstaticvoidmain(String[]argv)
{
//...same...
}
//Apathisalistofcells,i.e.,alistofCoordinstances.
staticLinkedList<Coord>solutionPath;

[Link]

16/20

1/15/2016

AlgorithmsandDataStructuresI

staticvoidsolveMaze(Mazemaze,Coordstart,Coordend)
{
//We'[Link]:

[Link]();
//Markthestartcellasvisited.

[Link](start);
//Createthelist.

solutionPath=newLinkedList<Coord>();
//Recursivelyfindthepathandfillincoord'sintothelist.

recursivelyFindPath(maze,start,end);
//[Link]?
[Link](start);
//PassthepathintotheGUI.

[Link](solutionPath);
}
staticbooleanrecursivelyFindPath(Mazemaze,Coordc,Coordend)
{
//Ifwe'vereachedtheend,we'redone.

if(([Link]==[Link])&&([Link]==[Link])){

returntrue;

}
//Otherwise,let'sfindaneighbortoexplore.

Coord[]validNeighbors=[Link](c);

if(validNeighbors==null){
//Ifwecouldn'tfindanyneighborstoexplore,we'restuck.

returnfalse;

}
//Tryeachneighbor,asmanyasneeded.
for(inti=0;i<[Link];i++){
//Tryneighbori.

[Link](validNeighbors[i]);

booleanfound=recursivelyFindPath(maze,validNeighbors[i],end);

if(found){
//Noticethatweaddthistothefrontofthelist,andonly
//afterthesolutionhasbeenfounduptohere.

[Link](validNeighbors[i]);

returntrue;

//Ifneighborididn'tworkout,undothevisitandcontinue.

[Link](validNeighbors[i]);

}
//Ifwereachedhere,thennoneoftheneighborsworkedout.

returnfalse;
}
}

TheNQueensproblem

Inthisproblem:
WearegivenanNxNchessboardandMqueens(whereM<=N).
Thegoalistoplacethequeensontheboardsothatnoqueen"attacks"another.
[Link]

17/20

1/15/2016

AlgorithmsandDataStructuresI

Forexample(N=8):

Recallthataqueencanattackanysquareinitsrow,columnordiagonal,e.g.

Wewillofcoursesolvethisrecursively:
Thisisanotherexampleofrecursionwithbacktracking.
Keyideas:
We'llproceedcolummbycolumn(lefttoright).
Whensolvingforthecurrentcolumn,trytoplaceaqueenoneachpossiblerow,andsolvethesub
problem(startingwiththenextcolumn)recursively.
Pseudocode:
Algorithm:solve(n,c)
Input:n=thenumberofqueenstoassign,c=thecolumntostartwith

//...Bottomoutconditions...(we'lldothislater)
[Link]
[Link][r,c]isanonattackedsquare
[Link][r,c]
[Link]=solve(n1,c+1)//Assignremainingn1recursively
[Link](found)
[Link]
[Link]
[Link]
[Link]
[Link]

18/20

1/15/2016

AlgorithmsandDataStructuresI

//Wereachhereifnoneoftherowsincolumncworkedout.
[Link]

Thus,wetryeveryrowforaqueenandtrytosolvethesubproblemwithfewerqueens.
=>Ififthatgetssolved,wecanplacethequeenthereandrecursebackup
Thebottomoutconditions:
Checkiftherearenomorequeenstoassign
=>Problemgetssolved.
Checkiftherearenomorecolumnstotry
=>Nosolutionexists.
WewillbuildaclasscalledChessBoardwithmethodsthathidemostofthemessyboardmanipulationdetails:
addQueen(row,col):addaqueeninsquare[row,col].
removeQueen(row,col):removethequeeninsquare[row,col].
booleanisForbidden(row,col):seeif[row,col]isanattackedsquare.
display():tobringupaGUIwiththeboarddisplayed.
Here'stheprogram:(sourcefile)
[Link].*;
[Link].*;
publicclassNQueens{
staticChessBoardboard;
publicstaticvoidmain(String[]argv)
{
solveQueens(8,8);
}
staticvoidsolveQueens(intnumQueens,intsize)
{
board=newChessBoard(size);
booleansolutionExists=solve(numQueens,0);
if(!solutionExists){
[Link]("Nosolutionfor"+numQueens+"ona"+size+"x"+size+"board");
return;
}
[Link]("Solutionfoundfor"+numQueens+"ona"+size+"x"+size+"board");
[Link](board);
[Link]();
}

staticbooleansolve(intnumQueens,intwhichCol)
{
//Bottomoutcondition1:
if(numQueens==0){
//Nonetoassigndone.
returntrue;
}

//Bottomoutcondition2:
if(whichCol>=[Link]()){
//Nocolumnslefttotrydone.
returnfalse;
}

//Tryeveryunforbiddenspotineachrow.
for(introw=0;row<[Link]();row++){
if(![Link](row,whichCol)){

[Link]

19/20

1/15/2016

AlgorithmsandDataStructuresI

//Trythislocation.
[Link](row,whichCol);

booleansolutionExists=solve(numQueens1,whichCol+1);
if(solutionExists){
returntrue;
}
//Else,undo
[Link](row,whichCol);
}
}

//Couldn'tfindasolution.
returnfalse;
}
}

[Link]

20/20

You might also like