【问题标题】:Doubly-Linked list Parent pointer changing双向链表父指针变化
【发布时间】:2018-09-07 03:44:21
【问题描述】:

实现一个贪婪的解决方案来解决和 8-puzzle

贪婪.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();
};

贪婪.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 };
}

我遇到了一个问题,当我展开更多节点时,指向 State 成员父级的指针正在发生变化。

State 有一个成员变量 State * parent。这用于在找到解决方案后返回到起点以使解决方案移动。

展开第一个节点后,优先级队列看起来正常,所有节点的父节点都是根节点,其父节点为NULL。然而,在第二个节点之后,我的优先级队列中的节点都指向刚刚扩展的节点!这些应该指向他们各自的父母,而不应该捆绑在一起。我似乎无法在这里找到我要去哪里,任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 你能让代码更简洁吗?阅读时间太长,似乎大部分与您的问题无关......

标签: c++ pointers greedy sliding-tile-puzzle


【解决方案1】:

问题在于Greedy::doGreedy 和您对current 的使用。

分配current = greedyQueue.top(); 创建队列中顶部对象的副本。稍后,当您调用vector&lt;State&gt; childrenFound = current.expandNode(); 时,所有返回的状态都有指向current 的父指针。在下一次循环迭代中,您再次对 current 进行赋值,更改所有返回状态所指向的父级。

您的代码没有简单的修复方法。您需要重新考虑如何存储 State 对象,以便父对象保持不变且不被修改。通常这种事情是通过堆栈或列表完成的,将每个节点添加到末尾并弹出它们以向上移动到父节点。

【讨论】:

  • 嗯,你是对的,问题与那个“电流”有关。所以被创建的孩子指向的是“当前”而不是他们被创建时持有的任何“当前”?这样说对吗?如果我将“当前”设为状态*,是否会消除对“当前”中当前内容的依赖?
  • 我明白了!我将“State current”更改为“stackvisitedStates”,然后每当我想获得当前正在处理的状态时,我都可以通过说visitedStates.top() 来获得它。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2013-11-15
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-11
  • 2020-12-20
  • 2014-12-13
相关资源
最近更新 更多