简体   繁体   English

Java Arraylist堆实现

[英]Java Arraylist Heap Implementation

I am trying to implement an insert() method for an arraylist-based heap implementation, but whenever I test the method inserting more than one integer where at least one of them is greater than ~4 the program takes forever to run. 我正在尝试为基于arraylist的堆实现实现insert()方法,但是每当我测试该方法插入多个整数(其中至少一个整数大于4)时,该程序将永远运行。 For example, stating heap.insert(1) and heap.insert(8) together in the main function will take forever to run. 例如,在main函数中同时声明heap.insert(1)heap.insert(8)将永远花费时间。 Here is my heap class: 这是我的堆类:

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();
    }
}

This is the pseudocode given to us by my professor that I modeled the insert() and siftUp() methods from: 这是我的教授给我们的伪代码,我从以下位置对insert()siftUp()方法进行了建模: 方法的伪代码

The program works for small integers, for example, if I type heap.insert(1) a bunch of times in a row, but never finishes running if I change one of the numbers to a larger integer. 该程序适用于较小的整数,例如,如果我连续多次键入heap.insert(1) ,但如果将其中一个数字更改为较大的整数,则永远无法完成运行。 No errors are thrown, as it doesn't finish executing when I try to run the program. 没有抛出任何错误,因为当我尝试运行该程序时,它没有完成执行。 I'm not sure what's going on. 我不确定发生了什么。 Any help is appreciated. 任何帮助表示赞赏。

Let's walk through your code here for a moment: 让我们在这里浏览一下代码:

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);
}

Now, you do the tree.insert(1) , and everything works fine. 现在,您执行tree.insert(1) ,一切正常。 Next you call tree.insert(0) . 接下来,您调用tree.insert(0) Let's see what happens. 让我们看看发生了什么。

  • tree.add(tree.size(), obj) adds 0 as the next item in the array list. tree.add(tree.size(), obj)将0添加为数组列表中的下一项。 So you now have a list that contains [1, 0] 因此,您现在有了一个包含[1, 0]的列表
  • the code calls siftUp(1) 代码调用siftUp(1)
  • in siftUp , the first line gets element 1 from the array list. siftUp ,第一行从数组列表中获取元素1。 At this point, v = 1 此时, v = 1
  • at the while statement, the code compares the value, 1, to the value at tree[k/2] . while语句中,代码将值1与tree[k/2]处的值进行比较。 Since k == 1 , you're checking against the root node (ie tree[0] ), which we know is equal to 1. 因为k == 1 ,所以您要检查根节点(即tree[0] ),我们知道它等于1。
  • Because the new value is smaller than its parent, you copy the parent value to the new item's position. 因为新值小于其父项,所以您可以将父项值复制到新项目的位置。 At this point, your array list contains [1, 1] . 此时,您的数组列表包含[1, 1]
  • You divide your index, k , by 2, giving 0. 您将索引k除以2,得到0。
  • Now you're back to the while condition. 现在,您回到了while条件。 k is equal to 0 and the value at tree[k] is 1, meaning that it's still greater than the value of v. k等于0,并且tree[k]值为1,这意味着它仍大于v的值。
  • You're now in an infinite loop, continually comparing the value at index 0 with your temporary value. 您现在处于无限循环中,不断将索引0处的值与您的临时值进行比较。

The problem is that your loop has no definite ending condition. 问题是您的循环没有确定的结束条件。

One way to solve the problem is to end the loop if k == 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);
}

The next trouble you're going to have is that your calculation of the parent node is incorrect. 下一个麻烦是父节点的计算不正确。 If the root node of the heap is at index 0, then for a node at index ix , its left child is at (ix*2)+1 , and the right child is at (ix*2)+2 . 如果堆的根节点在索引0处,那么对于索引ix处的节点,其左子节点在(ix*2)+1 ,而右子节点在(ix*2)+2 The node's parent is at (ix-1)/2 . 节点的父节点位于(ix-1)/2

Consider the heap with three nodes: 考虑具有三个节点的堆:

        0
      1   2

Here the node numbers are the same as the array indexes. 这里的节点号与数组索引相同。

If the root is at index 0, then the left node is at (2 * 0) + 1. The right node is at (2 * 0) + 2. The parent of 1 is (1-1)/2. 如果根在索引0处,则左侧节点在(2 * 0)+ 1处。右侧节点在(2 * 0)+ 2处。1的父节点是(1-1)/ 2。 And the parent of 2 is (2-1)/2. 2的父级是(2-1)/ 2。 In your code, you parent calculation is k/2 , which would give an incorrect value of 1 for the node labeled 2 in the heap above. 在您的代码中,父计算为k/2 ,对于上面堆中标记为2的节点,其错误值为1。

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

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