Java 使用数组实现最小堆:插入和删除最小值(使用重复项)

Java 使用数组实现最小堆:插入和删除最小值(使用重复项),java,arrays,data-structures,heap,min-heap,Java,Arrays,Data Structures,Heap,Min Heap,我试图在Java中实现一个Min堆,但在插入和删除元素(最后插入,删除根作为Min)方面遇到了问题。它似乎在很大程度上起作用(我使用一个程序直观地显示堆,并在删除min时打印出新的根,诸如此类) 我的问题是,由于某种原因,当添加一个新项目时,根目录不会切换到一个新项目,但我根本不明白为什么。而且,这似乎只是当存在大量重复项时的问题,堆似乎不能完全保持有序(父堆比子堆小)。在大多数情况下,确实如此。只是偶尔不会,对我来说,这似乎是随机的 这是通过泛型完成的,基本上遵循大多数算法。事实上,我所知道的

我试图在Java中实现一个Min堆,但在插入和删除元素(最后插入,删除根作为Min)方面遇到了问题。它似乎在很大程度上起作用(我使用一个程序直观地显示堆,并在删除min时打印出新的根,诸如此类)

我的问题是,由于某种原因,当添加一个新项目时,根目录不会切换到一个新项目,但我根本不明白为什么。而且,这似乎只是当存在大量重复项时的问题,堆似乎不能完全保持有序(父堆比子堆小)。在大多数情况下,确实如此。只是偶尔不会,对我来说,这似乎是随机的

这是通过泛型完成的,基本上遵循大多数算法。事实上,我所知道的一切都是有效的,这两种方法肯定有问题

public void insert(T e)  {
    if (size == capacity)
        increaseSize(); //this works fine

    last = curr; //keeping track of the last index, for heapifying down/bubbling down when removing min
    int parent = curr/2;
    size++; //we added an element, so the size of our data set is larger


    heap[curr] = e; //put value at end of array

    //bubble up
    int temp = curr;

    while (temp > 1 && ((Comparable<T>) heap[temp]).compareTo(heap[parent]) < 0) { //if current element is less than the parent
        //integer division
        parent = temp/2;
        swap(temp, parent); //the swapping method should be correct, but I included it for clarification
        temp = parent; //just moves the index value to follow the element we added as it is bubbled up
    }

    curr++; //next element to be added will be after this one


}

public void swap(int a, int b){
    T temp = heap[a];
    heap[a] = heap[b];
    heap[b] = temp;
}


public T removeMin() {

    //root is always min
    T min = heap[1];

    //keep sure array not empty, or else size will go negative
    if (size > 0)
        size--;

    //put last element as root
    heap[1] = heap[last];
    heap[last] = null;

    //keep sure array not empty, or else last will not be an index
    if (last > 0)
        last--;

    //set for starting at root
    int right = 3;
    int left = 2;
    int curr = 1;
    int smaller = 0;

    //fix heap, heapify down
    while(left < size && right < size){ //we are in array bounds

        if (heap[left] != null && heap[right] != null){ //so no null pointer exceptions
            if (((Comparable<T>)heap[left]).compareTo(heap[right]) < 0) //left is smaller
                smaller = left;
            else if (((Comparable<T>)heap[left]).compareTo(heap[right]) > 0) //right is smaller
                smaller = right;
            else //they are equal
                smaller = left;
        }
        if (heap[left] == null || heap[right] == null)//one child is null
        {
            if (heap[left] == null && heap[right] == null)//both null, stop
                break;
            if (heap[left] == null)//right is not null
                smaller = right;
            else //left is not null
                smaller = left;
        }


        if (((Comparable<T>)heap[curr]).compareTo(heap[smaller]) > 0)//compare smaller or only child
        {
            swap(curr,smaller); //swap with child
            curr = smaller; //so loop can check new children for new placement
        }
        else //if in order, stop
            break;

        right = 2*curr + 1; //set new children
        left = 2*curr;
    }


    return min; //return root
}
公共作废插入(TE){
如果(大小=容量)
increaseSize();//这很好
last=curr;//跟踪最后一个索引,以便在删除最小值时向下堆化/向下冒泡
int parent=curr/2;
size++;//我们添加了一个元素,因此数据集的大小更大
heap[curr]=e;//将值放在数组末尾
//冒泡
温度=电流;
而(temp>1&((compariable)heap[temp]).comparieto(heap[parent])<0{//如果当前元素小于父元素
//整数除法
父母=临时工/2;
swap(temp,parent);//交换方法应该是正确的,但为了澄清起见,我将其包括在内
temp=parent;//只要将索引值移动到我们添加的冒泡元素后面即可
}
curr++;//要添加的下一个元素将位于该元素之后
}
公共无效掉期(整数a、整数b){
T temp=堆[a];
堆[a]=堆[b];
堆[b]=温度;
}
公共T removeMin(){
//根总是最小的
T min=堆[1];
//确保数组不为空,否则大小将变为负数
如果(大小>0)
大小--;
//将最后一个元素作为根
堆[1]=堆[last];
heap[last]=null;
//确保数组不为空,否则last将不是索引
如果(上次>0)
最后--;
//设置为从根开始
int右=3;
int左=2;
int curr=1;
int小于等于0;
//固定堆,堆下来
而(left0)//right更小
较小=右侧;
否则,他们是平等的
较小=左;
}
if(heap[left]==null | | heap[right]==null)//一个子项为null
{
如果(heap[left]==null&&heap[right]==null)//都为null,则停止
打破
如果(heap[left]==null)//right不为null
较小=右侧;
else//left不为空
较小=左;
}
if(((可比)heap[curr]).compareTo(heap[small])>0//比较较小的或唯一的子级
{
交换(当前,较小);//与子级交换
curr=smaller;//因此循环可以检查新子项的新位置
}
否则//如果顺序正确,请停止
打破
right=2*curr+1;//设置新的子项
左=2*电流;
}
return min;//返回根
}

方法中没有声明的任何变量都是全局变量,我知道有两件事情可能是多余的,比如add中的整个current/last/temp情况,所以对此我很抱歉。我试图让所有的名字都不言自明,并解释我在removeMin中做的所有检查。任何帮助都会得到疯狂的感谢,我已经尽我所能查找和调试了。我想我基本上缺少了一些东西。

为了帮助您进行调试,您应该简化代码。“last”变量有点奇怪。同样在“insert”中,当您执行循环时,temp可能应该变为0,也就是说

while (temp >= 0 &&......

为了帮助您调试,您应该简化代码。“last”变量有点奇怪。同样在“insert”中,当您执行循环时,temp可能应该变为0,也就是说

while (temp >= 0 &&......

您是否使用IDE以便调试代码?是的,我使用eclipse,以便调试。我还使用GraphViz将堆显示为树状结构。老实说,我并不擅长使用调试器,通常在打印语句方面比较幸运,因此我可能会因为这种不称职而错过一些东西。您是否使用IDE以便调试代码?是的,我使用eclipse,以便调试。我还使用GraphViz将堆显示为树状结构。老实说,我并不擅长使用调试器,通常在打印语句方面运气更好,所以我可能会因为这种无能而错过一些东西。