我正在尝试为基于arraylist的堆实现实现insert()
方法,但每当我测试插入多个整数的方法时,其中至少有一个大于~4,程序将永远执行跑。例如,在main函数中一起声明heap.insert(1)
和heap.insert(8)
将永远运行。这是我的堆类:
import java.util.*;
public class Heap<E extends Comparable<E>> implements HeapAPI<E>
{
/**
* A complete tree stored in an array list representing this
* binary heap
*/
private ArrayList<E> tree;
/**
* Constructs an empty heap
*/
public Heap()
{
tree = new ArrayList<E>();
}
public boolean isEmpty()
{
return tree.isEmpty();
}
public void insert(E obj)
{
tree.add(tree.size(), obj);
siftUp(tree.size() - 1);
}
/**
* siftUp from position k. The key or node value at position
* may be greater that that of its parent at k/2.
* @param k position in the heap arraylist
*/
private void siftUp(int k)
{
E v = tree.get(k);
while (v.compareTo(tree.get(k / 2)) == 1)
{
tree.add(k, tree.get(k / 2));
k = k / 2;
}
tree.add(k, v);
}
public int size()
{
return tree.size();
}
}
这是我教授给我们的伪代码,我将insert()
和siftUp()
方法建模为:
该程序适用于小整数,例如,如果我连续多次键入heap.insert(1)
,但如果我将其中一个数字更改为更大的整数,则永远不会运行。不会抛出任何错误,因为当我尝试运行程序时它没有完成执行。我不知道发生了什么。任何帮助表示赞赏。
答案 0 :(得分:1)
让我们来看看你的代码片刻:
public void insert(E obj)
{
tree.add(tree.size(), obj);
siftUp(tree.size() - 1);
}
private void siftUp(int k)
{
E v = tree.get(k);
while (v.compareTo(tree.get(k / 2)) == 1)
{
tree.add(k, tree.get(k / 2));
k = k / 2;
}
tree.add(k, v);
}
现在,您执行tree.insert(1)
,一切正常。接下来,您致电tree.insert(0)
。让我们看看会发生什么。
tree.add(tree.size(), obj)
将0添加为数组列表中的下一个项目。所以你现在有一个包含[1, 0]
siftUp(1)
siftUp
中,第一行从数组列表中获取元素1。此时,v = 1
while
语句中,代码将值1与tree[k/2]
处的值进行比较。自k == 1
以来,您要检查根节点(即tree[0]
),我们知道它等于1。[1, 1]
。k
除以2,得0。while
状态了。 k
等于0,tree[k]
的值为1,表示它仍然大于v的值。问题是你的循环没有明确的结束条件。
解决问题的一种方法是在k == 0
。
private void siftUp(int k)
{
E v = tree.get(k);
while (k > 0 && v.compareTo(tree.get(k / 2)) == 1)
{
tree.add(k, tree.get(k / 2));
k = k / 2;
}
tree.add(k, v);
}
您将遇到的下一个问题是您对父节点的计算不正确。如果堆的根节点位于索引0,则对于索引为ix
的节点,其左子节点位于(ix*2)+1
,右侧子节点位于(ix*2)+2
。节点的父级位于(ix-1)/2
。
考虑具有三个节点的堆:
0
1 2
此处节点编号与数组索引相同。
如果根位于索引0,则左节点位于(2 * 0)+ 1.右节点位于(2 * 0)+ 2.父节点为(1-1)/ 2 。并且2的父亲是(2-1)/ 2。在您的代码中,您的父计算是k/2
,对于上面堆中标记为2的节点,它将给出不正确的值1。