【问题标题】:How come my stack is getting overwritten after a for loop execution?为什么我的堆栈在 for 循环执行后被覆盖?
【发布时间】:2014-02-25 03:00:34
【问题描述】:

我正在为爬山搜索做一个算法,由于某种原因,我应该在循环结束时拥有的堆栈似乎被循环生成的状态的最后一次迭代所覆盖。

基本上,这里是这个算法正在做的事情的概要:

这个算法被用来解决N皇后问题。具有状态类的所有底层代码都可以正常工作。使用此算法,它会遍历当前状态的所有可能的后续状态。它将下一个后继状态存储在 neighborState 变量中(如下面的代码所示)。如果状态成本小于当前成本,它会将具有新低成本的邻居状态添加到邻居节点中,并将其存储到堆栈中。任何检测到的新最小值都将擦除堆栈并插入新的最低最小值节点。

我已经在循环中进行了一些测试,以查看插入到堆栈中的输出是什么样的。他们似乎都在正确输出。但是,当我在循环之外并检查堆栈时,堆栈中的所有节点都将其状态替换为循环中最后生成的后继状态。似乎在每个存储了neighborState 的节点中,每次neighborState 更新时,它也会更改所有节点的neighborState 值。不过,我似乎无法找到解决此问题的方法。

我将不胜感激有关如何解决此问题的一些建议!

*注意:忽略从 if 语句开始的 for 循环之后的代码,因为它仍然不完整。

代码如下:

import java.util.Random;
import java.util.Stack;

public class HillClimber {

private LocalSearchNode _current;
private int _shoulderSearchStepsAllowed;

// may need more instance variables

public HillClimber(LocalSearchNode initial, int searchShoulder) {
    _current = initial;
    _shoulderSearchStepsAllowed = searchShoulder;
}

public LocalSearchNode findSolution() {
    LocalSearchNode neighborNode = null;
    //Stack <LocalSearchNode> nodeStack;
    State currentState = null;
    //State neighborState = null;
    Double val = 0.0;
    boolean start = true;

    while (true) {

        currentState = _current.getState();
        Stack<LocalSearchNode> nodeStack = new Stack<LocalSearchNode>();

        // finds the highest valued successor of current
        for (String s : currentState.actions()) {
            State neighborState = currentState.successor(s);
            Double cost = neighborState.estimatedDistance(neighborState);

            // execute this for the first successor found
            if (start) {
                val = cost;
                System.out.println("Started with " + val);
                neighborNode = new LocalSearchNode(neighborState,
                        s, val, 0);
                nodeStack.push(neighborNode);
                start = false;
                ((QState) nodeStack.peek().getState()).test();
                System.out.println(nodeStack.size());
            }
            // resets node array if new min found and adds it to the array
            else if (cost < val) {
                System.out.println("Reset " + val + " with " + cost);
                val = cost;
                nodeStack = new Stack<LocalSearchNode>();
                neighborNode= new LocalSearchNode(neighborState,
                        s, val, 0);
                nodeStack.push(neighborNode);
                ((QState) nodeStack.peek().getState()).test();
                System.out.println(nodeStack.size());
            }
            // if cost is the same as current min val, add it to the array
            else if (cost.equals(val)) {
                val = cost;
                System.out.println("Added " + val);
                neighborNode = new LocalSearchNode(neighborState,
                        s, val, 0);
                nodeStack.push(neighborNode);
                ((QState) nodeStack.peek().getState()).test();
                System.out.println(nodeStack.size());
            }
        }

        System.out.println("Final min " + val);
        System.out.println(nodeStack.size());
        ((QState) nodeStack.elementAt(0).getState()).test();
        ((QState) nodeStack.elementAt(1).getState()).test();

        // returns current state if no better state found
        if (_current.getValue() < val) {
            // System.out.println(val);
            // ((QState) _current.getState()).test();
            return _current;
        } else {
            if (nodeStack.size() > 1) {
                Random generator = new Random();
                int i = generator.nextInt(nodeStack.size());
                _current = nodeStack.elementAt(i);
            } else {
                _current = nodeStack.firstElement();
            }
            start = true;
        }
    }
}

}

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class QState implements State {
private List<String> _list;
private int[][] _state;
private int[] _qlist;

/**
 * Constructor takes in the board and row index value corresponding to the
 * queens at their respective column index
 * 
 * @param state
 * @param queens
 */
public QState(int[][] state, int[] queens) {
    _state = state;
    _qlist = queens;

    _list = new ArrayList<String>();

    // generates a list of all possible actions for this state
    for (int i = 0; i < _qlist.length; i++) {
        for (int j = 0; j < _qlist.length; j++) {
            if (_state[i][j] != -1) {
                _list.add("Move queen " + j + " to row " + i);
            }
        }
    }
}

/**
 * Returns a list of N * (N - 1) actions
 */
public List<String> actions() {
    return _list;
}

/**
 * Returns the matrix board configuration of this state
 * 
 * @return
 */
public int[][] getMatrix() {
    return _state;
}

/**
 * Returns the array of queens row index for the board configuration
 * 
 * @return
 */
public int[] getQList() {
    return _qlist;
}

/**
 * Parses the action and moves the queen to the new board location
 */
public State successor(String action) {
    State temp = null;
    int[][] newState = _state;
    int[] newQList = _qlist;

    String[] vals = action.split("\\s");
    int i = Integer.parseInt(vals[5]); // parses the row index
    int j = Integer.parseInt(vals[2]); // parses the column index

    newState[_qlist[j]][j] = 0; // clears the old queen
    newState[i][j] = -1; // sets the new queen
    newQList[j] = i; // adds the new queen to the list

    temp = new QState(newState, newQList);
    return temp;
};

/**
 * Returns the default step cost of 1.0
 */
public Double stepCost(String action) {
    return 1.0;
}

// overrides the built-in Java equals method
@Override
public boolean equals(Object s) {
    if (s == null) {
        return false;
    }

    if (this.getClass() != s.getClass()) {
        return false;
    }

    if (!Arrays.equals(this.getMatrix(), ((QState) s).getMatrix())) {
        return false;
    }
    return true;
}

/**
 * Returns the queen conflicts for the particular board
 */
public Double estimatedDistance(State s) {
    double conflicts = 0.0;
    int col = 0;
    int row = 0;

    for (int j = 0; j < _qlist.length; j++) {
        row = _qlist[j] - 1;
        col = j + 1;

        // checks the upper right diagonal for queen conflicts
        while (row >= 0 && col < _qlist.length) {
            if (_state[row][col] == -1) {
                conflicts++;
            }
            row--;
            col++;
        }

        row = _qlist[j] + 1;
        col = j + 1;

        // checks the lower right diagonal for queen conflicts
        while (row < _qlist.length && col < _qlist.length) {
            if (_state[row][col] == -1) {
                conflicts++;
            }
            row++;
            col++;
        }

        row = _qlist[j];
        col = j + 1;

        // checks the sideways right for queen conflicts
        while (col < _qlist.length) {
            if (_state[row][col] == -1) {
                conflicts++;
            }
            col++;
        }
    }
    // test();
    return conflicts;
}

public void test() {
    for (int i = 0; i < _qlist.length; i++) {
        for (int j = 0; j < _qlist.length; j++) {
            if (_state[i][j] == -1) {
                System.out.print("Q");
            } else {
                System.out.print("-");
            }
        }
        System.out.println("");
    }
    System.out.println("\n");
}

}

【问题讨论】:

  • 当您在代码的 2 个位置创建新堆栈时可能实现错误。
  • “它也改变了所有节点的neighborState 值” 这听起来就像你只有一个neighborState 对象。另外,不幸的是,我认为我们无法从给出的代码中确定错误的来源。只是猜测一下。显示的代码过于间接,而且它使用的类不是来自 JDK。
  • @Radiodef 我已经添加到我的 QState 类中,这是程序使用的另一个类。除此之外,初始棋盘是随机生成的,在各自的列中有 N 个皇后。

标签: java algorithm search nodes hill-climbing


【解决方案1】:

如果您查看successor,我觉得这很可疑:

int[][] newState = _state;
int[] newQList = _qlist;

在这里,您似乎在对象之间共享这些数组。在不太了解程序正在做什么的情况下,这种事情通常是您观察到的“共享更新”行为的原因。

所以从返回的后继者更新数组也会改变返回它的对象的状态(等等)。

有几种简单的方法可以复制数组,即System#arraycopyArrays#copyOfclone。 (所有数组都是可克隆的。)对于 2D 数组,您可能需要创建一个辅助方法,因为您可能需要进行深层复制。比如:

static int[][] copyState(int[][] toCopy) {
    int[][] copy = new int[toCopy.length][];
    for(int i = 0; i < copy.length; i++) {

        // or   = Arrays.copyOf(toCopy[i], toCopy[i].length);
        copy[i] = toCopy[i].clone();
    }

    return copy;
}

我并没有花很多时间来真正解析代码——还有很多事情要做,抱歉——但我没有看到你在任何地方制作副本,只是对它们进行变异,所以我把我敢打赌。

【讨论】:

  • 非常感谢!这已经解决了问题! :D
  • 太棒了。乐意效劳。 :)
猜你喜欢
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多