Origin:
Hanoi Tower (also known as Hanoi Tower) the problem is a puzzle toy originated from an ancient Indian legend. When the great Brahman created the world, he made three diamond pillars. On one pillar, 64 gold discs were stacked in size order from bottom to top. The great Brahman ordered the Brahman to rearrange the discs on another pillar in size order from below. And it was stipulated that they could not be placed on small discs Zoom in on the disc and move only one disc at a time between the three columns.
Abstract as a mathematical problem:
As shown in the figure below, there are three columns a, B and C from left to right. There are n discs stacked from small to large on column A. now it is required to move the disc on column a to column C. There is only one principle: only one plate can be moved at a time, and the large plate cannot be on the small plate. Calculate the moving steps and times
Solution: (1) n == 1
1st time: panel 1 a --- > C sum = 1 st time
(2) n == 2
1st time: panel 1 a --- > b
2nd time: panel 2 a --- > C
The 3rd time --- panel 1 --- B --- > C --- sum = 3 times
(3)n == 3
1st time: panel 1 a --- > C
2nd time: panel 2 a --- > b
3rd time: panel 1 C --- > b
4th time: panel 3 A --- > C
5th time: panel 1 B --- > A
6th batch 2 B --- > C
The 7th time --- panel 1 --- a --- > C --- sum = 7 times
It is not difficult to find the law: the first power of the number of times 2 of a disk minus 1
The number of times of two discs is 2 to the power of 2 minus 1
The number of times of three discs is 2 to the third power minus 1
. . . . .
The number of n discs minus 1 to the nth power of 2
Therefore, the number of moves is: 2^n - 1
There are two solutions, one is recursion and the other is stack. Let's first look at the implementation of recursion
- Move n - 1 discs from A to C (with the aid of B)
- Move the n th disc from A to B
- Move n - 1 discs from C to B (with the aid of A)
The number of moves is 2 to the nth power - 1
let count = 0 function move(number, from, to, depend) { console.log(`Will be the first ${number} No. 1 disc from ${from} Move to ${to}`) count++ } // Move n discs from a to b by means of c function hanoi(n, a, b, c) { if (n === 0) { return } hanoi(n - 1, a, c, b) // Move n -1 discs from a to c with the aid of b move(n, a, b) // Move the n th disc from a to b hanoi(n - 1, c, b, a) // Move n -1 discs from c to b with the aid of a } hanoi(3, 'A', 'B', 'C') console.log('Number of moves', count) // Move disc No. 1 from A to B // Move disc No. 2 from A to C // Move disc No. 1 from B to C // Move disc No. 3 from A to B // Move disc No. 1 from C to A // Move disc No. 2 from C to B // Move disc No. 1 from A to B // Number of moves 7
Refactor the above, using a function
function hanoiRecursion(n, a, b, c, moves = []) { if (n === 0) { return moves } hanoiRecursion(n - 1, a, c, b, moves) // Move n -1 discs from a to c with the aid of b moves.push([a, b]) // move(n, a, b) / / move the nth disc from a to B hanoiRecursion(n - 1, c, b, a, moves) // Move n -1 discs from c to b with the aid of a return moves } let moves = hanoiRecursion(3, 'A', 'B', 'C') console.log('Move path', moves) console.log('Number of moves', moves.length) // //Move path // // [ // // ["A", "B"], ["A", "C"], ["B", "C"], ["A", "B"], // // ["C", "A"], ["C", "B"], ["A", "B"] // // ] // //Number of moves 7
In fact, recursion is also required to use the stack, but we can see the corresponding effect in real time by representing three cylinders through three stacks
// Stack class class Stack { constructor() { this.count = 0; this.items = {}; } // Insert element into stack push(element) { this.items[this.count] = element; this.count++; } isEmpty() { return this.count === 0; } size() { return this.count; } get length() { return this.count; } // Pop element from stack pop() { if (this.isEmpty()) { return undefined; } this.count--; const result = this.items[this.count]; delete this.items[this.count]; return result; } peek() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } clear() { this.items = {}; this.count = 0; // perhaps // while(!this.isEmpty()) { // this.pop() // } } toString() { if (this.isEmpty()) { return ""; } else { let i = 0, len = this.count, result = ""; while (i < len) { result += this.items[i]; if (i !== len - 1) { result += ","; } i++; } return result; } } } function hanoi(n, source, dest, depend, a, b, c, moves = []) { if (n === 0) { return } // Move n - 1 discs from source to depend ent hanoi(n - 1, source, depend, dest, a, c, b, moves) moves.push([a, b]) // Move the n th disc from source to dest dest.push(source.pop()) // Move n - 1 discs from depend ent to dest hanoi(n - 1, depend, dest, source, c, b, a, moves) } function hanoiStack(n) { let source = new Stack() let dest = new Stack() let depend = new Stack() let count = n while (count) { source.push(count--) } let moves = [] console.log('source: ', source) hanoi(n, source, dest, depend, 'A', 'B', 'C', moves) console.log('source: ', source) console.log('dest: ', dest) console.log('depend: ', depend) return moves } console.log(hanoiStack(3)) // source: Stack { count: 3, items: { '0': 3, '1': 2, '2': 1 } } // source: Stack { count: 0, items: {} } // dest: Stack { count: 3, items: { '0': 3, '1': 2, '2': 1 } } // depend: Stack { count: 0, items: {} } // [ // [ 'A', 'B' ], // [ 'A', 'C' ], // [ 'B', 'C' ], // [ 'A', 'B' ], // [ 'C', 'A' ], // [ 'C', 'B' ], // [ 'A', 'B' ] // ]