Algorithm 二进制堆插入,don';我不懂循环
在Weiss的《Java中的数据结构和算法》中,他解释了二进制堆的插入算法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
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