问题
I read through a few of the discussions about the Towers of Hanoi problem. I understand the recursive solution using the following code:
void Hanoi3(int nDisks, char source, char intermed, char dest)
{
if(nDisks == 1){
cout << "Move the plate from " << source << " to " << dest << endl;
}
else{
Hanoi3(nDisks - 1, source, dest, intermed);
cout << "Move the plate from " << source << " to " << dest << endl;
Hanoi3(nDisks - 1, dest, intermed, source);
}
}
What I actually need to do is output some type of "illustration" of the towers at each step. I'm having a lot of trouble accomplishing this. Our instructor suggested using stacks to keep track of what disk is on what tower, but I'm having trouble outputting this as finding and outputting the values in the stacks requires popping off the top entries and deleting them. They become lost, if I understand it correctly.
Either way, it led me to some solution that starts off like this:
void Hanoi(int nDisks, stack<int> source, stack<int> intermed, stack<int> dest){
if(nDisks == 1){
dest.push(source.top());
source.pop();
}
else{
Hanoi(nDisks - 1, source, dest, intermed);
dest.push(source.top());
source.pop();
Hanoi(nDisks - 1, dest, intermed, source);
}
}
int main()
{
int nDisks;
cout << "Enter the number of disks: ";
cin >> nDisks;
stack<int> source, intermed, dest;
for(int i = nDisks; i >= 1; i--){
source.push(i);
}
Hanoi(nDisks, source, intermed, dest);
return 0;
}
I'm well aware that this is wrong. I'm not sure where a good place would be to populate source with the disk numbers. And I'm passing down the same size source stack each time. If someone could give me some direction or anything, that would be really cool. Thank you.
回答1:
Pass a reference to the stacks:
stack<int>&
Also consider using a vector rather than a stack so you can iterate it to see the current content of the towers.
PigBen's answer also correctly identifies a bug in your code where you're not moving the disks from the intermediate tower to the destination tower.
回答2:
Pass the stacks by reference, and change the order you pass them in the last step so that you are moving from intermed to dest, using source as the intermediate.
void Hanoi(int nDisks, stack<int> &source, stack<int> &intermed, stack<int> &dest){
if(nDisks == 1){
dest.push(source.top());
source.pop();
}
else{
Hanoi(nDisks - 1, source, dest, intermed);
dest.push(source.top());
source.pop();
Hanoi(nDisks - 1, intermed, source, dest);
}
}
To display the stack, just copy it and pop from the copy.
回答3:
Consider your original code:
void Hanoi3(int nDisks, char source, char intermed, char dest)
{
if(nDisks == 1){
cout << "Move the plate from " << source << " to " << dest << endl;
}
else{
Hanoi3(nDisks - 1, source, dest, intermed);
cout << "Move the plate from " << source << " to " << dest << endl;
Hanoi3(nDisks - 1, dest, intermed, source);
}
}
It's not correct, so that's possibly why your teacher suggests presenting the towers.
As you note, a std::stack
is a good container to use to represent a tower's current disks, but as you also note, it's not entirely straightforward to get at the elements of a std::stack
without popping them. You can pop them and push them down on another stack, and move them back, but that's intricate and silly, not to mention inefficient for the general case. That's why std::stack
has a protected
member c
, the underlying container, that you can access by deriving from the class.
There are no virtual members in std::stack
, so the only purpose of having a protected
member is to make it slightly hard to get at. I think it's a bad design decision. But it's what you have, so,
#include <iostream>
#include <string>
#include <stack>
#include <stddef.h>
using namespace std;
typedef ptrdiff_t Size;
typedef Size Index;
class IntStack
: public stack<int>
{
public:
Size count() const { return size(); }
int at( Index i ) const { return c[i]; }
};
class Hanoi
{
private:
IntStack towers_[3];
int nDisks_;
public:
Hanoi( int nDisks )
: nDisks_( nDisks )
{
for( int disk = nDisks; disk >= 1; --disk )
{
towers_[0].push( disk );
}
}
IntStack const& towers( Index i ) const { return towers_[i]; }
};
int main()
{
int const nDisksTotal = 2;
Hanoi puzzle( nDisksTotal );
for( Index i = 0; i < 3; ++i )
{
IntStack const& tower = puzzle.towers( i );
Size const nDisks = tower.count();
cout << "Tower " << i << ": ";
for( Index diskPos = 0; diskPos < nDisks; ++diskPos )
{
if( diskPos > 0 ) { cout << ", "; }
cout << tower.at( diskPos );
}
cout << endl;
}
}
Note that this code only illustrates how you can access the elements of those stacks.
The display can be made much more fancy, e.g. graphical.
I suggest you make your solver function a member of class Hanoi
. And add a member function to display the puzzle state. Later you might want to turn that into a callback, in order to support a graphical user interface.
EDIT: hm, I see another answer has shown "the solution" for the bug. That removes the OP's learning experience and the whole reason for displaying the towers. This answer intentionally only affirmed that the bug is real, and showed instead what the OP asked for, namely how to display stacks, efficiently.
Cheers & hth.,
来源:https://stackoverflow.com/questions/4481224/towers-of-hanoi-question