在删除 c ++ 时维护最小堆

Posted

技术标签:

【中文标题】在删除 c ++ 时维护最小堆【英文标题】:Maintaining a Min heap on deletion c++ 【发布时间】:2017-08-24 02:58:18 【问题描述】:

测试用例:

8,7,5,2,3,6,9(不是最小堆)(这是 buildHeap 函数的元素 A*)

2,3,5,7,8,6,9(调用构建堆后的最小堆)

3,5,6,7,8,9(在调用 deleteMin 之后)这是不正确的

应该是这个3,7,5,9,8,6

我似乎无法找到 deleteMin 的问题,我知道我的 heapify 正在工作,但我可能没有看到任何东西。

 Element Heap::deleteMin(Heap& heap)
    Element deleted = heap.H[0];
    heap.H[0] = heap.H[heap.size-1];
    heap.size--;
    cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
    for(int i=heap.capacity/2-1;i>=0;--i)
       heapify(heap,i);
    return deleted;


void Heap::heapify(Heap& heap,int index)
    int smallest = 0;
    int left = 2*index;
    int right = 2*index+1;

    if(left < heap.size && heap.H[left].getKey() < heap.H[index].getKey())
        smallest=left;
    else 
       smallest=index;
    if(right < heap.size && heap.H[right].getKey() < heap.H[smallest].getKey())
        smallest=right;
    if(smallest != index)
        int swapKey = heap.H[index].getKey();
        heap.H[index].setKey(heap.H[smallest].getKey());
        heap.H[smallest].setKey(swapKey);
        heapify(heap,smallest);
    



void Heap::buildHeap(Heap& heap, Element* A)
        for(int j=0;j<heap.capacity;++j)
                heap.insert(heap,A[j]);
                for(int i=heap.capacity/2-1;i>=0;--i)
                        heapify(heap,i);
        

【问题讨论】:

您是否尝试使用调试器单步执行您的代码? 我们不知道“heapify”应该做什么,所以除了“heapify 正在做它正在做的事情”之外我们不能说什么。但是,我会注意到您的语句“if(smallest != index)”,其中您将数组中的值与数组的索引进行比较,这看起来肯定不正确 - 例如,如果您将 100 添加到所有数组中的值(如 108,107、105 等),那么对于 7 个元素的数组,该条件将始终返回 false - 它看起来不正确。 @racraman:heapify 是实现堆时的常见操作。它在堆中筛选一个项目。它通常也称为siftDown。如果您更仔细地检查heapify,您会发现smallest 是数组的索引,而不是数组中的值。 【参考方案1】:

第一个问题是您对子索引的计算是错误的。如果你使用H[0] 作为堆的根,那么

left = (2*index)+1
right = (2*index)+2

您的计算假设根位于H[1]

另一个问题是你在 deleteMin 函数中做了太多工作:

Element Heap::deleteMin(Heap& heap)
    Element deleted = heap.H[0];
    heap.H[0] = heap.H[heap.size-1];
    heap.size--;
    cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
    for(int i=heap.capacity/2-1;i>=0;--i)
        heapify(heap,i);
    return deleted;

删除最小项并将最后一项放入堆中的根后,您只需调用heapify(heap, 0); 在该循环中没有理由重新构建整个堆。

所以你的函数变成了:

Element Heap::deleteMin(Heap& heap)
    Element deleted = heap.H[0];
    heap.H[0] = heap.H[heap.size-1];
    heap.size--;
    cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
    heapify(heap, 0);
    return deleted;

您的buildHeap 方法同样做了太多工作。

您可能对堆的复习感兴趣。我在http://blog.mischel.com/2013/09/29/a-better-way-to-do-it-the-heap/ 的博客文章用非常简单的术语解释了它们的操作,我的simple heap of integers 显示了一个简单的实现。它使用 C# 而不是 C++,但代码非常相似。你应该可以毫无困难地理解它。

【讨论】:

以上是关于在删除 c ++ 时维护最小堆的主要内容,如果未能解决你的问题,请参考以下文章

手动实现最小堆和最大堆(优先队列)

时间复杂度最小的堆插入和删除

黑匣子

n个最小和贪心思想,利用堆维护

优先队列的实现(最小堆)

实现最小堆类