Towers of Hanoi question

人盡茶涼 提交于 2019-12-23 03:05:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!