A collection of non-recursive algorithms for Hanoi Tower problem
Qiao is clumsy (welcome reprint, but please specify Source: Http://blog.csdn.net/qiaoruozhuo )
Hanoi Tower Problem Description:
In India, there is an old legend: in the world center of Sheng Miao (in northern India), a yellow copper plate is inserted with three stone needles. In the creation of the world, The Hindu god Brahma, on one of the needles, dressed from the bottom to the top 64 pieces of gold, the so-called Hanoi. No matter the day or night, there is always a monk in accordance with the following rules to move these pieces of gold, one at a time, no matter where the needle, the small pieces must be on top of the large. The world will be wiped out in a thunderbolt when all the gold is moved from the needle on which Brahma is dressed, and the Vatican, the temple and all sentient beings will perish.
Hanoi Tower problem recursive algorithm simple and concise code, is one of the most beautiful code:
int count = 0;//global variable, cumulative operation steps void Hanoi (int n, char A, char B, char c)//recursive algorithm {if (n = = 1)//If there is only one disk, move it directly from the A-column to the C-pillar printf ("%d: %d%c,%c ", ++count, N, a, c); Else{hanoi (N-1, A, C, b);//using C-pillar relay, move n-1 disks from A to B-pillar printf ("%d:%d%c---%c " , ++count, N, a, c);//Move the nth disk from column A to column C Hanoi (n-1, B, A, c);//Use a-column relay to move the n-1 disk from the B-pillar to the C-pillar}}
However, the non-recursive algorithm is not so easy to understand, the author compiled the following several programs (there are several options, because I do not understand, temporarily do not post, at the same time, please be smart to add a concise and easy to understand algorithm, thank you!) )
The common idea is to use the stack of recursive algorithm for non-recursive conversion, Li Chunbao teacher compiled the "Data structure (c language)--Exercises and Analysis" (Tsinghua University Press) a method is introduced. This method designs a data structure of the struct Act {int flag,num; Char x, y, Z;} S[2000]; Stores the current operation information, where flag==0 means to move the NUM number disc directly, otherwise it needs to be further decomposed; Num represents the current operation of moving the plate number, x, Y, Z for the current operation of the 3 columns, namely the departure column, the midpoint column and the target column.
The basic idea of the algorithm and the middle sequence traversal binary tree is very similar, in-depth understanding of the algorithm, I made some improvements to the code in the book, so that it is more concise and clear. The code is as follows:
void Hanoi_1 (int n, char A, char B, char c)//non-recursive algorithm 1{struct Act {int flag, num; Char x, y, Z;} S[2000]; Storing the current operation information, flag==0 represents the direct move num number disc, otherwise need to further decompose int top, M;char ta, TB, TC; S[0].flag = 1;//initial value into the stack s[0].num = n; s[0].x = A; S[0].y = b; S[0].z = C;top = 0;count = 0;while (top >= 0) {if (S[top].flag = = 0 | | S[top].num = = 1)//move the NUM disk from X directly to z{printf ("%d:%d%c-/%c ", ++count, S[top].num, s[top].x, s[top].z);--top;} else { //extract stack top information m = s[top].num; ta = s[top].x;tb = S[TOP].Y;TC = s[top].z; Will be Hanoi (n-1, B, A, c); Operation into the stack, covering the original stack top information s[top].num = m-1; s[top].x = TB; S[top].y = TA; S[TOP++].Z = TC; Move the M-disk from the A-column to the C-post operation into the stack s[top].flag = 0; S[top].num = m; s[top].x = TA; S[TOP++].Z = TC; Will be Hanoi (N-1, A, C, b); Operation into the stack s[top].flag = 1; S[top].num = m-1; s[top].x = TA; S[TOP].Y = TC; S[top].z = TB; }}}
Non-recursive algorithm 1 is a recursive algorithm simulation process, but because it divides the current operation into two types, namely, direct movement and further decomposition, artificially increase the complexity of the algorithm. In fact, careful analysis of the binary tree in the middle sequence traversal non-recursive algorithm (see my book "the most concise and understandable non-recursive traversal binary tree algorithm in historyhttp://blog.csdn.net/qiaoruozhuo/article/details/40586443), we can find that a similar method can be used to transform Hanoi non-recursive algorithm into a non-recursive algorithm, the way of thinking is almost identical. The code is as follows:
void hanoi_2 (int n, char A, char B, char c)//non-recursive algorithm 2{struct Act {int num; Char x, y, Z;} S[max]; Store current operation information int top = -1;int count = 0;while (n > 0 | | Top >= 0) {if (n > 0)//Enter stack and search left child, upcoming Hanoi (N-1, A, C, b); Operation into stack { s[++top].num = n--; s[top].x = A; S[top].y = b; S[top].z = C; A = S[top].x;b = S[top].z;c = S[top].y; } else//output and back stack, search right child, will be Hanoi (n-1, B, A, c); Operation into stack {printf ("%d:%d-%c--and%c ", ++count, S[top].num, s[top].x, s[top].z); n = s[top].num-1;a = S[top].y;b = S[top ].x;c = S[top--].z;}} }
The non-recursive algorithm 1 and 2 is the basic method of using stack simulation recursive process, we can also analyze the problem of the Nottingham tower from another angle. For the question of the Nottingham with n plates, the steps to be 2^n–1, if each step as a node, just make up a tree full of two, tree height h and plate number of the relationship is h==n. The number of layers of the node and the corresponding plate is level==n+1-level, that is, plate 1 on the nth layer, plate n on the 1th layer, and if the operation of a node is "Plate N from A->c", then its left child operation is "plate n-1 from A->b", right child operation as " The plate n-1 from the b->c "; the middle sequence traverses the two-forked tree, and the number of nodes corresponds to the order of movement.
So we can construct a tree full of two forks and then traverse the two-fork tree in the middle sequence. The code is as follows:
void Hanoi_3 (int n, char A, char B, char c)//non-recursive algorithm 3, disadvantage is the need for secondary space too large {struct act {int num; Char x, y, Z;} BT[132000]; Store a full two fork tree for each step, assuming n<=17. int S[max] = {0};int I, top, count = 0; Bt[1].num = n;//is the root node assignment bt[1].x = A; Bt[1].y = b; bt[1].z = C;n = Pow (2, n-1); for (I=1; i<n; i++)//Assign value {bt[i+i].num = Bt[i+i+1].num = Bt[i].num-1 for each node's left and right child; bt[i+i].x = Bt[i+i+1].y = bt[i].x; Bt[i+i].z = bt[i+i+1].x = Bt[i].y; Bt[i+i].y = Bt[i+i+1].z = bt[i].z;} Middle sequence traversal full two fork tree n + = n; i = 1;top = -1;while (i < n | | Top >= 0) {if (I < n)//into the stack, and search left child { S[++top] = i; i + = i;} else//output and stack, search for right child {i = s[top--]; printf ("%d:%d%c,%c ", ++count, Bt[i].num, bt[i].x, bt[i].z); i + = i + 1; } }}
The idea of algorithm 3 is simple and easy to understand, the code is very concise, but there is a fatal flaw, is the need for too much auxiliary space, when n is not very suitable for large. Is there a better way?
In fact, have come to this step, and then carefully observe the tree full of two, you can find more laws (please draw the reader to the full two-tree map, in order to facilitate the understanding of the algorithm). Here are my observations:
The relationship between the height H of ① tree and the number of plates is h==n. The number of layers in which the node is located is Level==n+1-level, that is, plate 1 on the nth layer, and plate n on the 1th floor;
② the sequence of two forks, the number of nodes exactly corresponds to the order of movement.
③ N-level 2^ (n-1) nodes, which can be divisible by 2^0 and not divisible by 2^1:1,3,5,7,9,... 2^n-1.
The n-1 layer 2^ (n-2) nodes, which can be divisible by 2^1 and not divisible by 2^2:2,6,10,14,... 2^n-2.
......
The 3rd layer has a total of 2^2 nodes, which cannot be divisible by 2^ (n-2): 2^ (n-3) * 1, 2^ (n-3) * 2, 2^ (n-3) * 3, 2^ (n-3) * 4
The 2nd layer has a total of 2^1 nodes, which cannot be divisible by 2^ (n-1): 2^ (n-2) * 1, 2^ (n-2) * 2
The 1th layer has a total of 2^0 nodes, it cannot be divisible by 2^n: 2^ (n-1) * *
The operations of ④ odd-level nodes are: A->c, C->b, B->a, A->c, C->b, B->a 、... Die 3 cycle;
The operation of each node in the even-numbered layer is: A->b, B->c, C->a, A->b, B->c, C->a 、... Die 3 cycle;
Combined with the above analysis, the following conclusions are drawn
① number of plates N determined, the total number of steps m=2^n-1;
② the number of layers at step I (0<i<2^n) is determined, when I can be divisible by 2^ (N-J) and cannot be divisible by 2^ (N+1-J), I is at Layer J;
③ I (0<i<2n) steps in the order number of Layer J (starting from 0) k=i/s, where s = 2<< (N-J);
Based on the above analysis, we can give the corresponding code:
void Hanoi_4 (int n, char A, char B, char c)//non-recursive algorithm 4, according to the law of full two fork output {int I, level, K, s;int m = 1<<n; For (I=1, i<m; i++) {for (s=2,level=n; i%s==0; s=s<<1)//judgment is the first layer of the node {--level;} K = i/s; Is the first leve k+1 node printf ("%d:%d", I, n+1-level); if (level & 1)//Odd layer {switch (k% 3) {case 0:printf ("A-C "); Break;case 1:printf ("C-B") ; Break;cas E 2:printf ("B-A ");}} else //even layer {switch (k% 3) {case 0:printf ("A-B "); Break;case 1:printf ("B-C "); Break;case 2:pri NTF ("C-A ");}} }}
Algorithms 3 and 4 belong to the method of using full two fork tree features, Shangba teacher in the "mathematical nutrition dish" mentioned an American scholar discovered method, as long as take two steps in turn to do it.
First, the three pillars are sorted in sequence, and all the discs are placed on column A in order from large to small. Determine the order of the pillars according to the number of discs: if n is even, place a B C in the clockwise direction, and if n is odd, place a C b in a clockwise direction.
(1) in the clockwise direction of the disk 1 from the current column to the next column, that is, when n is even, if the disk 1 in column A, then move it to B; If the disk 1 is in column B, move it to C; If the disk 1 is in column C, move it to a.
(2) Next, move the movable discs of the other two pillars to the new pillars. That is, the disk on the non-empty pillar is moved to the empty column, when the two pillars are non-empty, move the smaller disc. This step does not specify which disk to move, you may think there are many possibilities, in fact, the action can be implemented is unique.
(3) repeated (1) (2) operation, finally can be completed according to the provisions of the Hanoi movement.
With this step, the code is easy to write. The code is as follows:
void Hanoi_5 (int n, char A, char B, char c)//non-recursive algorithm 5 {struct pillars {int S[max], top; char pos;} P[3]; Store the tray information on each pillar int i, count, Next, Pre;for (i=0; i<n; i++) {p[0]. S[i] = n-i;} P[0].pos = A; P[0].top = n-2; Number 1th is not in the stack p[1].top = P[2].top = -1;if (n 2 = = 0) {P[1].pos = b; P[2].pos = C;} Else{p[1].pos = C; P[2].pos = b;} n = Pow (2, N)-1; Count = i = 0;while (Count < N) {printf ("%d:1%c and%c", ++count, P[i%3].pos, p[(i+1)%3].pos);//Move the 1th from clockwise to the next pillar if (count = = n) break;++i; Next = (i+ 1)% 3;pre = (i-1)% 3;if (P[next].top < 0 | | P[pre].top >= 0 && P[pre]. S[p[pre].top] < P[next]. S[p[next].top]) {P[next]. S[++p[next].top] = P[pre]. s[p[pre].top--];//move the plate on the previous pillar to the next pillar printf ("%d:%d-%c,%c", ++count, P[next]. S[p[next].top], P[pre].pos, P[next].pos); }else{p[pre]. S[++p[pre].top] = P[next]. s[p[next].top--];//move the plate on the next pillar to the previous pillar printf ("%d:%d-%c,%c", ++count, P[pre]. S[p[pre].top], P[next].pos, P[pre].pos); }}}
Hanoi Tower problem is broad and profound, I collected a little bit, to get so many methods, there are a number of ways to understand the moment, not posted out, please the vast number of netizens to discuss, share more and better ways.
A collection of non-recursive algorithms for Hanoi Tower problem