可以在没有队列或堆栈的情况下实现BFS吗?

时间:2016-09-05 02:11:33

标签: java algorithm breadth-first-search

我想知道如何在不使用队列或hashTable的情况下执行此操作,而是使用固定数组作为查找表。这是我用于解决2x2 rubiks立方体的BFS算法。我想要做的是将其解决方案搜索到的所有位置存储在一个文件中,这样如果我要给程序一个加扰的多维数据集,它将搜索多维数据集的状态并打印出解决方案。

static private void solve(Cube c) {
    Set<Cube> cubesFound = new HashSet<Cube>();
    cubesFound.add(c);

    Stack<Cube> s = new Stack<Cube>();
    s.push(c);

    Set<Stack<Cube>> initialPaths = new HashSet<Stack<Cube>>();
    initialPaths.add(s);

    solve(initialPaths, cubesFound);
}

static private void solve(Set<Stack<Cube>> livePaths, Set<Cube> cubesFoundSoFar) {
    System.out.println("livePaths size:" + livePaths.size());
    int numDupes = 0;

    Set<Stack<Cube>> newLivePaths = new HashSet<Stack<Cube>>();

    for(Stack<Cube> currentPath : livePaths) {

        Set<Cube> nextStates = currentPath.peek().getNextStates();

        for (Cube next : nextStates) {
            if (currentPath.size() > 1 && next.isSolved()) {
                currentPath.push(next);
                System.out.println("Path length:" + currentPath.size());
                System.out.println("Path:" + currentPath);
                System.exit(0);

            } else if (!cubesFoundSoFar.contains(next)) {
                Stack<Cube> newCurrentPath = new Stack<Cube>();
                newCurrentPath.addAll(currentPath);
                newCurrentPath.push(next);
                newLivePaths.add(newCurrentPath);
                cubesFoundSoFar.add(next);
            } else {
                numDupes += 1;
            }
        }
    }

    System.out.println("Duplicates found " + numDupes + ".");
    solve(newLivePaths, cubesFoundSoFar);
}


private Cube() {
    cube = new int[][] {
        { 0, 0, 0, 0 },
        { 1, 1, 1, 1 },
        { 2, 2, 2, 2 },
        { 3, 3, 3, 3 },
        { 4, 4, 4, 4 },
        { 5, 5, 5, 5 }
    };
    cube = scanCube(cube);
    cube = print_cube(cube);
 //scanCube is just a method that takes input of the state of the cube in 2d array form
 //print_cube is a method formats the 2d array to look like a flat cube.
}

private Cube(Cube other) {
    cube = new int[other.cube.length][];
    for (int i = 0; i < other.cube.length; i++) {
        cube[i] = Arrays.copyOf(other.cube[i], other.cube[i].length);
    }

}



private boolean isSolved() {
    for (int i = 0; i < cube.length; i++) {
        for (int k = 1; k < cube[i].length; k++) {
            if (cube[i][0] != cube[i][k]) {
                return false;
            }
        }
    }
    return true;
}

@Override
public boolean equals(Object other) {

     return other instanceof Cube && Arrays.deepEquals(((Cube) other).cube, cube);
}

1 个答案:

答案 0 :(得分:0)

让我们想一想为什么BFS需要一个队列,而DFS需要一个堆栈。基本上,对于特定图,对于算法可以遍历的任何节点,图的所述节点可以具有尚未被访问的多个相邻节点。毕竟,此属性是将图表与列表区分开来的最重要的属性之一:节点可能有多个连接或没有连接。事实上,如果您的算法要处理的图形不是非常具体的,那么在任何节点上,您可能会有 O(N)节点作为要访问的相邻节点,N是该图中的节点数。

现在,因为你有 O(N)节点作为下一个目的地,而不是 O(1),一个(或少数节点变量不能被视为足以存储您的下一个目的地。

存储多个下一个目的地的核心需求是根据队列的使用情况。您可以通过将未来目标列表保留在数组中或文件中来避免使用队列。但你对该阵列或文件所做的基本上是实现队列的功能:允许 O(1)插入和删除以及 O(1)的数据集合访问元素。

我并不是说这种做法完全没用。例如,对自定义队列实现的这种需求可能来自具有有限的存储器或磁盘空间来存储元件。它可能会降低时间效率,因为人们必须考虑文件访问和修改或维护固定大小队列所做的其他簿记工作的大部分不变因素。尽管如此,这种自定义队列实现仍可能是合法使用的。

但是,我对这些自定义实现的主要看法是,即使您将其存储在其他位置或保持大小固定,您仍然使用队列,并且您将不得不继续使用某种形式的队列,只要BFS工作的图数据结构中的邻接关系的定义没有以革命性的方式重新定义,导致在节点上只有 O(1)下一个目的地。目前,我认为没有队列的BFS可以在没有队列的情况下工作的唯一类型的图是链表,并且只有从列表的开头开始。