繁体   English   中英

Java Arraylist堆实现

[英]Java Arraylist Heap Implementation

我正在尝试为基于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) ,但如果将其中一个数字更改为较大的整数,则永远无法完成运行。 没有抛出任何错误,因为当我尝试运行该程序时,它没有完成执行。 我不确定发生了什么。 任何帮助表示赞赏。

让我们在这里浏览一下代码:

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-1)/ 2。 2的父级是(2-1)/ 2。 在您的代码中,父计算为k/2 ,对于上面堆中标记为2的节点,其错误值为1。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM