【问题标题】:BFS: PriorityQueue not getting emptyBFS:PriorityQueue 没有变空
【发布时间】:2014-01-31 18:50:32
【问题描述】:

所以我想解决我上一篇文章中描述的问题:Terrain/Mountain algorithm not working as intended。问题的副本如下:

我想使用一个非常基本的原理创建一个上面有山的地形,如下图所示:

0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 1 2 3 2 1 0 0 0
0 0 1 2 3 4 3 2 1 0 0
0 0 0 1 2 3 2 1 0 0 0
0 0 0 0 1 2 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

它从height = 4 的随机点开始,然后逐渐减少它的邻居。

递归的思路很简单,我开始一个点,用height - 1(在这个例子中)递归到上/下/左/右,只有还没有遇到时,我才设置它们的值。

所以我继续使用 BFS 实现它:

private void createMountain(final float[][] heightMapping, final float startHeight) {
    boolean[][] traversed = new boolean[width][depth];
    boolean positive = (startHeight >= 0f);
    int x = random.nextInt(width);
    int z = random.nextInt(depth);
    PriorityQueue<QueueElement> priorityQueue = new PriorityQueue<>((o1, o2) -> (int)Math.signum(o1.height - o2.height));
    priorityQueue.offer(new QueueElement(x, z, startHeight));
    while (!priorityQueue.isEmpty()) {
        QueueElement current = priorityQueue.poll();
        if (current.x < 0 || current.x >= width || current.z < 0 || current.z >= depth) {
            continue;
        }
        if (traversed[current.x][current.z]) {
            continue;
        }
        if ((positive && current.height <= 0f) || (!positive && current.height >= 0f)) {
            continue;
        }
        heightMapping[x][z] = current.height;
        priorityQueue.offer(new QueueElement(x, z - 1, calculateNewHeight(current.height, positive)));
        priorityQueue.offer(new QueueElement(x, z + 1, calculateNewHeight(current.height, positive)));
        priorityQueue.offer(new QueueElement(x - 1, z, calculateNewHeight(current.height, positive)));
        priorityQueue.offer(new QueueElement(x + 1, z, calculateNewHeight(current.height, positive)));
    }
}

private class QueueElement {
    public int x, z;
    public float height;

    public QueueElement(final int x, final int z, final float height) {
        this.x = x;
        this.z = z;
        this.height = height;
    }
}

private float calculateNewHeight(final float startHeight, final boolean positive) {
    float delta = startHeight / maxDecayFactor;
    return (positive) ? startHeight - delta : startHeight + delta;
}

现在代码永远不会停止,我尝试调试了几次,但要么没有得到有用的结果,要么地形完全平坦。

我目前唯一真正的线索是priorityQueue.size() 一直在增加 3。
有人知道发生了什么吗?

更新:即使在修复之后,它仍然无法按预期工作。

0.6  0.5  0.4  0.3  0.3  0.2  0.2  0.1  0.1  0.1  0.1  0.1  0.0  0.0  0.0  0.0  
0.8  1.0  1.2  1.6  1.9  2.4  3.0  3.8  4.7  5.9  7.4  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  
0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  

可能有什么问题? PriorityQueue 现在搞砸了吗?

【问题讨论】:

    标签: java algorithm priority-queue breadth-first-search java-8


    【解决方案1】:

    您在轮询新元素时忘记设置traversed[x][z] = true;
    请确保在查询 if (traversed[current.x][current.z]) ... 后执行此操作

    另外,作为旁注,对于您的实施 - 我认为Queue 将是一个更好的主意。 (当我写一个 PriorityQueue 会更好时,我想到了多个峰值 - 这对你来说似乎不是这样,我认为一个简单的队列会是最好的)。

    【讨论】:

    • 我正在重新定位 traversed[x][z] = true 并忘记将其放回原处。但实际上更多的事情是错误的,我现在添加了一个 epsilon 值,而且我需要在大多数情况下使用 current.xcurrent.z,而不是最初的 xz!我现在唯一的问题是地形看起来仍然不对,我将在 OP 中添加额外的输出。
    • 使用LinkedBlockingQueue 它现在突然起作用了!我还不知道为什么它不适用于PriorityQueue
    • @skiwi 您将什么作为比较器函数放入优先级队列?
    • PriorityQueue&lt;QueueElement&gt; priorityQueue = new PriorityQueue&lt;&gt;((o1, o2) -&gt; (int)Math.signum(o1.height - o2.height));,它使用 lambdas 速记表示最大值。
    • @skiwi 我认为它的发生是因为您为已经在优先级队列中(更深)的对象更改了o2.height - 这导致了这种行为,但我可能是错的。
    猜你喜欢
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 2016-08-24
    • 2014-06-17
    • 2014-02-07
    • 1970-01-01
    相关资源
    最近更新 更多