Java Arraylist堆实现

时间:2017-02-13 18:26:27

标签: java algorithm arraylist data-structures heap

我正在尝试为基于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()方法建模为: Pseudocode for Methods

该程序适用于小整数,例如,如果我连续多次键入heap.insert(1),但如果我将其中一个数字更改为更大的整数,则永远不会运行。不会抛出任何错误,因为当我尝试运行程序时它没有完成执行。我不知道发生了什么。任何帮助表示赞赏。

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的值。
  • 您现在处于无限循环中,不断将索引0处的值与您的临时值进行比较。

问题是你的循环没有明确的结束条件。

解决问题的一种方法是在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。