Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 二进制堆插入,don';我不懂循环_Algorithm_Binary Heap - Fatal编程技术网

Algorithm 二进制堆插入,don';我不懂循环

Algorithm 二进制堆插入,don';我不懂循环,algorithm,binary-heap,Algorithm,Binary Heap,在Weiss的《Java中的数据结构和算法》中,他解释了二进制堆的插入算法 public void insert( AnyType x ) { if( currentSize == array.length -1) enlargeArray( array.length * 2 + 1); // Percolate up int hole = ++currentSize; for(array[0] = x; x.compareTo( array[ hole / 2

在Weiss的《Java中的数据结构和算法》中,他解释了二进制堆的插入算法

public void insert( AnyType x )
{
    if( currentSize == array.length -1)
        enlargeArray( array.length * 2 + 1);

    // Percolate up
int hole = ++currentSize;
for(array[0] = x; x.compareTo( array[ hole / 2 ]) < 0; hole /=2 )
    array[ hole ] = array[ hole / 2 ];
array[ hole ] = x;
}
public void insert(AnyType x)
{
if(currentSize==array.length-1)
放大阵列(array.length*2+1);
//渗透
int-hole=++currentSize;
对于(数组[0]=x;x.compareTo(数组[hole/2])<0;hole/=2)
数组[孔]=数组[孔/2];
数组[孔]=x;
}

我知道在树上移动一个洞的原理,但我不明白他是如何在for循环中使用这种语法实现的……初始化器
array[0]是什么意思=x;
mean?他似乎在覆盖根值?这似乎是一段非常做作的代码。他在做什么?

数组初始化器看起来有问题。如果是数组[hole]=x;,那么整个事情就完全有意义了

它首先将值放在树的最低级别(当前大小之后的条目),然后通过查看(int)hole/2查找“它上面”的条目


它一直向上移动,直到比较器告诉它停止。我认为这是对for循环语法的轻微误用,因为它感觉像是真正的while(x.compare(hole/2)<0)类型的循环。

首先,我收到了Mark Weiss的回复,他的电子邮件基本上说代码是正确的(在这个答案的底部有完整的回复)

他还说:

因此,最小项位于数组索引1中,如findMin所示。要进行插入,请遵循从底部到根的路径

索引1?嗯……然后我不得不回去重新阅读本章的大部分内容,当我看到图6.3时,它点击了

数组是基于0的,但被视为堆一部分的元素是从索引1开始存储的。图6.3如下所示:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   | A | B | C | D | E | F | G | H | I | J |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  0   1   2   3   4   5   6   7   8   9  10  11  12  13
将值放置在元素0处是一个哨兵值,用于使循环终止

因此,通过上面的树,让我们看看insert函数是如何工作的。下面的
H
标记了孔

首先,我们将
x
放入第0个元素(堆外),并将洞放在数组中下一个可用元素上

                                              H
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| x | A | B | C | D | E | F | G | H | I | J |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  0   1   2   3   4   5   6   7   8   9  10  11  12  13
然后我们用气泡(过滤)这个洞,将值从“索引的一半”向上移动,直到找到放置
x
的正确位置

如果我们看一下图6.5和6.6,让我们将实际值放入数组中:

                           H/2                           H
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 14 | 13 | 21 | 16 | 24 | 31 | 19 | 68 | 65 | 26 | 32 |    |    |    |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
   0    1    2    3    4    5    6    7    8    9   10   11   12   13
请注意,我们将要插入的值14放入索引0中,但这在堆之外,我们的sentinel值用于确保循环终止

然后,我们将值
x
hole/2
处的值进行比较,该值现在为11/2=5。x小于31,因此我们向上移动该值并移动该孔:

            H/2             H <---------------------------
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 14 | 13 | 21 | 16 | 24 | 31 | 19 | 68 | 65 | 26 | 32 | 31 |    |    |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
   0    1    2    3    4    5    6    7    8    9   10   11   12   13
                            |                             ^
                            +--------- move 31 -----------+
如您所见,如果查看图6.6和图6.7,这与预期行为相匹配


因此,虽然代码没有错,但有一个小问题可能超出了本书的范围

如果插入的
x
类型是引用类型,则当前堆中会有2个对刚刚插入的同一对象的引用。如果立即从堆中删除该对象,它看起来(但首先看一下我们从哪里得到的…)与此类似,第0个元素仍将保留引用,从而禁止垃圾收集器执行其工作


为了确保这里没有隐藏的议程,下面是Mark的完整答案:

嗨,姑娘

代码是正确的

二进制堆是一个完整的二叉树,它位于 自下而上,值永远不会增加。因此,最小值 项位于根。数组表示法将根置于 索引1,对于索引i处的任何节点,父节点位于i/2(四舍五入) 向下)(左边的子项为2i,右边的子项为2i+1,但是 这里不需要)

因此,最小项位于数组索引1中,如中所示 要进行插入,请按照从下到下的路径进行 根

在for循环中:

hole/=2表示将孔移动到父对象的想法

x、 compareTo(array[hole/2])<0表达了我们留在其中的想法 只要x小于父循环,循环就会停止

问题是,如果x是一个新的最小值,你永远也出不去 安全地循环(从技术上讲,您在尝试比较x和数组[0]时崩溃)。 你可以做一个额外的测试来处理这个案子。 或者,代码通过在数组[0]中的 开始,由于节点i的“父节点”是i/2,因此 索引1中的根可以在索引0中找到。这保证了 如果x是新的最小值,则循环终止(然后放置x,其中 是索引1处根中的新最小值)

书中有一个较长的解释……但这里的基本概念是 使用sentinel(或dummy)值以避免为 边界情况

问候,

马克韦斯


它是从教科书中复制的。我现在修复了括号。老实说,这看起来像一个bug,他在数组中有两次
x
值,可能是在索引0处,循环停止循环的地方。似乎以前有人问过这个问题:我冒昧地向那本书的作者发送了一封电子邮件,链接到这个任务ion和我在上面评论的那个,但是在我等待的时候,也许其他人有一个很好的答案。谢谢!虽然你的版本似乎比我的版本旧,而且假定的错误仍然存在,所以我不知道这有多合理。Wowsers…非常令人印象深刻。我会在我有几分钟空闲的时候回来消化它。谢谢!!
       H/2   H <------------
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 14 | 13 | 21 | 16 | 24 | 21 | 19 | 68 | 65 | 26 | 32 | 31 |    |    |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
   0    1    2    3    4    5    6    7    8    9   10   11   12   13
             |              ^
             +-- move 21 ---+
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
| 14 | 13 | 14 | 16 | 24 | 21 | 19 | 68 | 65 | 26 | 32 | 31 |    |    |
+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
   0    1    2    3    4    5    6    7    8    9   10   11   12   13
             ^
             x