简体   繁体   中英

Doubly-Linked list Parent pointer changing

implementing a greedy solution to solve and 8-puzzle

Greedy.h:

class Greedy {
    const string Goal = "12345678_";
    State current;
    string startState;
    int nodesCreated, nodesExpanded;
    priority_queue<State> greedyQueue;
    set<string> visited;
    stack<string> solutionStack;    
public:
    Greedy(const string start);
    ~Greedy();    
    void doGreedy();
};

Greedy.cpp:

tuple<int, int> getTarget(int n);


Greedy::Greedy(const string start) : startState(start), nodesCreated(0), nodesExpanded(0) {}

Greedy::~Greedy() {}    

void Greedy::doGreedy() {
    greedyQueue.emplace(startState, "");
    while (!greedyQueue.empty()) {
        current = greedyQueue.top();
        greedyQueue.pop();
        if (visited.find(current.stateString) == visited.end()) {
            visited.insert(current.stateString);
            if (current.stateString == Goal) {  //end has been reached, calculate path, print out stats, and end.
                cout << "Solution Found!" << endl;
                //solutionStack.push(current.moveFromParent);
                State* tempParent = current.parent;
                while ( solutionStack.size() < 20 && tempParent != NULL) {
                    solutionStack.push(tempParent->moveFromParent);
                    tempParent = tempParent->parent;
                }
                break;
            }
            vector<State> childrenFound = current.expandNode();
            for (int i = 0; i < childrenFound.size(); ++i) {    // for each child found, add it to the priority queue, set its parent, and set it as a child of parent
                State temp = childrenFound[i];
                if (visited.find(temp.stateString) == visited.end()) {  // We haven't been here before, put it in the queue
                    greedyQueue.push(temp);
                }
            }
        }
    }
    cout << "Last 20 moves:" << endl;
    while (!solutionStack.empty()) {
        cout << solutionStack.top() << endl;
        solutionStack.pop();
    }
}

State.h:

class State {
public:
    string moveFromParent;
    State* parent;
    string stateString;
    int distance;
    State();
    State(const string str, State * _parent, string _moveFromParent);
    State (const string str, string _moveFromParent);
    State(const string str, int dist, State * _parent, string _moveFromParent);
    ~State();

    bool operator<(const State & state) const;
    bool operator==(const State & state) const;
    int findBlank();
    vector<State> expandNode();
};

State.cpp:

int manhattan(const string str);
tuple<int, int> getTarget(int n);

State::State() {}

State::State(const string str, State * _parent, string _moveFromParent) : stateString(str), moveFromParent(_moveFromParent) {
    parent = _parent;
}

State::State(const string str, string _moveFromParent) : stateString(str), moveFromParent(_moveFromParent) {
    parent = NULL;
    distance = manhattan(stateString);
}

State::State(const string str, int dist, State* _parent, string _moveFromParent) : stateString(str), distance(dist), moveFromParent(_moveFromParent) {
    parent = _parent;
    distance = manhattan(stateString);
}

State::~State() {}

bool State::operator<(const State & state) const {
    return distance > state.distance;
}

bool State::operator==(const State & state) const {
    return ((stateString == state.stateString));
}

int State::findBlank() {
    for (int i = 0; i < stateString.length(); ++i) {
        if (stateString[i] == '_') {
            return i;
        }
    }
}

vector<State> State::expandNode() {
    vector<State> returnStates;
    int blank = findBlank();
    if (blank % 3 > 0) { // can move left
        string newState = stateString;
        newState[blank] = newState[blank - 1];
        newState[blank - 1] = '_';
        int heuristic = manhattan(newState);
        State * childsParent = this;
        string move = "left";
        State temp = State(newState, heuristic, childsParent, move);
        returnStates.push_back(temp);
    }
    if (blank % 3 < 2) { //can move right
        string newState = stateString;
        newState[blank] = newState[blank + 1];
        newState[blank + 1] = '_';
        int heuristic = manhattan(newState);
        State * childsParent = this;
        string move = "right";
        State temp = State(newState, heuristic, childsParent, move);
        returnStates.push_back(temp);
    }
    if (blank / 3 > 0) { //can move up
        string newState = stateString;
        newState[blank] = newState[blank - 3];
        newState[blank - 3] = '_';
        int heuristic = manhattan(newState);
        State * childsParent = this;
        string move = "up";
        State temp = State(newState, heuristic, childsParent, move);
        returnStates.push_back(temp);
    }
    if (blank / 3 < 2) { // can move down
        string newState = stateString;
        newState[blank] = newState[blank + 3];
        newState[blank + 3] = '_';
        int heuristic = manhattan(newState);
        State * childsParent = this;
        string move = "down";
        State temp = State(newState, heuristic, childsParent, move);
        returnStates.push_back(temp);
    }
    return returnStates;
}

int manhattan(const string str) {
    int distance = 0;
    for (int i = 0, length = str.length(); i != length; ++i) {
        tuple<int, int> target;
        if (str[i] == '_') {
            target = { 2, 2 };
        }
        else {
            int temp = str[i] - '0';
            target = getTarget(temp);
        }
        tuple<int, int> current = getTarget(i + 1);
        int localSum = abs(get<0>(current) - get<0>(target)) + abs(get<1>(current) - get<1>(target));
        distance += localSum;
    }
    return distance;
}

tuple<int, int> getTarget(int n) {
    return { (n - 1) / 3, (n - 1) % 3 };
}

I'm having a problem where the pointer to the State member parent is changing when I expand more nodes.

State has a member variable State * parent. This is used to traverse back to the beginning after finding the solution in order to get the solution moves.

After expanding the first node, the priority queue looks normal, with the parent of all nodes being the root node, whose parent is NULL. After a second node, however, the nodes in my priority queue are all pointing to the node that was just expanded! These should be pointing to their individual parents, and should not be tied together. I can't seem to find where I'm going wrong here and any help would be appreciated. Thanks!

The problem is in Greedy::doGreedy and your usage of current .

The assignment current = greedyQueue.top(); creates a copy of the top object in the queue. Later, when you call vector<State> childrenFound = current.expandNode(); , all the returned states have parent pointers that refer to current . On the next loop iteration, you make that assignment to current again, changing the parent pointed to by all those returned states.

There isn't an easy fix with your code. You need to rethink how you store State objects so that the parent objects stay around and unmodified. Often this sort of thing is done with a stack or list, adding each node to the end and popping them off to move up to the parent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM