简体   繁体   English

用堆构建优先级队列

[英]Building a priority queue with a heap

If the heap is based on an array and the root is extracted, the code I'm using is suppose to reshuffle the nodes so that the heap property is maintained. 如果堆是基于数组的,并且提取了根,则我正在使用的代码应该重新组合节点,以便维护堆属性。

From my understanding the array and heap aren't exactly the same thing, but it seems that in the code, building the heap is just rearranging the array so that it holds the heap property. 从我的理解来看,数组和堆并不完全相同,但是在代码中,构建堆似乎只是重新排列了数组,使其拥有堆属性。 Is this the standard way to create the heap? 这是创建堆的标准方法吗? Is it necessary to fill another array instead of just altering the array it is based on? 是否有必要填充另一个数组而不是仅仅更改它所基于的数组?

I'm having trouble understanding this concept because when I remove the root using a function extract-max , unless I pop the element from the array the array remains the same size. 我很难理解这个概念,因为当我使用函数extract-max删除根时,除非我从数组中弹出元素,否则数组的大小将保持不变。 And the heap is supposed to be smaller but all that happens is that the node that moved up to replace the root is indicated by a zero in the array and it is not removed. 堆应该较小,但是所有发生的事情是,向上移动以替换根的节点在数组中用零表示,并且不将其删除。

If I do keep the structure where the heap is basically the array obeying the heap property, how do I remove the node that should no longer be part of the heap? 如果我确实保留了结构,即堆基本上就是遵循堆属性的数组,那么如何删除不再属于堆的节点? In my code this node is denoted by a 0 when printing the array. 在我的代码中,打印数组时,此节点用0表示。

#include <iostream>
#include <deque>
#include "print.h"
#include "random.h"

int parent(int i)
{
    return (i - 1) / 2;
}

int left(int i)
{
    if(i == 0)
        return 1;
    else
        return 2*i;
}

int right(int i)
{
    if(i == 0)
        return 2;
    else
        return 2*i + 1;
}

void max_heapify(std::deque<int> &A, int i, int heapsize)
{
    int largest;
    int l = left(i);
    int r = right(i);
    if(l <= heapsize && A[l] > A[i])
        largest = l;
    else
        largest = i;
    if(r <= heapsize && A[r] > A[largest])
        largest = r;
    if(largest != i) {
        exchange(A, i, largest);
        max_heapify(A, largest, heapsize);
    }
}

void build_max_heap(std::deque<int> &A)
{
    int heapsize = A.size() - 1;
    for(int i = (A.size() - 1) / 2; i >= 0; i--)
        max_heapify(A, i, heapsize);
}

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();
    //A.pop_front();
    A[0] = A[heapsize--];
    //A.pop_back();
    max_heapify(A, 0, heapsize);
    return max;
}

int main(int argc, const char * argv[])
{
    std::deque<int> B = deq(7);
    print(B);
    build_max_heap(B);
    print(B);
    std::cout << "Extract max ->\t" << heap_extract_max(B, B.size()) << std::endl;
    print(B);
    std::cout << "Extract max ->\t" << heap_extract_max(B, B.size()) << std::endl;
    print(B);
    return 0;
}

Output: 输出:

79 92 86 29 27 42 6 
92 86 79 29 27 42 6 
Extract max ->  92
86 79 42 29 27 0 6 
Extract max ->  86
79 42 27 29 0 0 6 

So. 所以。 I changed max-heapify to return an index to the node that should be eliminated. 我更改了max-heapify以将索引返回到应消除的节点。

int max_heapify(std::deque<int> &A, int i, int heapsize)
{
    int largest;
    int l = left(i);
    int r = right(i);
    if(l <= heapsize && A[l] > A[i])
        largest = l;
    else
        largest = i;
    if(r <= heapsize && A[r] > A[largest])
        largest = r;
    if(largest != i) {
        exchange(A, i, largest);
        int j = max_heapify(A, largest, heapsize);
        return j;
    }
    return i;
}

Then I erased the element in heap_extract_max 然后我擦除了heap_extract_max的元素

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();
    A[0] = A[heapsize--];
    int i = max_heapify(A, 0, heapsize);
    A.erase(A.begin() + i);
    return max;
}

I get this output for 11 elements: 我得到11个元素的输出:

79 10 61 99 28 12 51 96 13 37 83 
99 96 83 79 37 61 51 10 13 28 12 
Extract max ->  99
96 83 61 79 37 12 51 10 13 28 
Extract max ->  96
83 79 61 51 37 12 10 13 28 

I really thought initially that I'd just be able to pop the last element after its value was recorded into the root and then reorganize the heap, but it wasn't cooperating. 最初,我真的以为我可以在将最后一个元素的值记录到根之后弹出最后一个元素,然后重新组织堆,但是并没有合作。 So the alternative was to delete the node position after the heap was reorganized. 因此,替代方法是在重组堆之后删除节点位置。

Going back to the original code: 回到原始代码:

I realized where the problem was. 我意识到问题出在哪里。 I need to decrement the heapsize before I index the array using the variable, not after. 我需要在使用变量而不是之后对数组进行索引之前减小堆大小。 Then I can just pop the last element the way I intended. 然后,我可以按预期方式弹出最后一个元素。

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();
    A[0] = A[--heapsize];
    A.pop_back();
    max_heapify(A, 0, heapsize);
    //int i = max_heapify(A, 0, heapsize);
    //A.erase(A.begin() + i);
    return max;
}

Your heap_extract_max function is discarding the last element in the std::deque . 您的heap_extract_max函数正在丢弃std::deque的最后一个元素。

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();  // Get a copy of the first element
    A[0] = A[heapsize--]; // Copy the last element to the first element
                          // and reduce the heap size, effectively 
                          // discarding the last element.
    max_heapify(A, 0, heapsize);
    return max;
}

after this, you can safely use pop_back() on your std::deque to remove that element from the container if you want. 之后,您可以根据需要在std::deque上安全地使用pop_back()从容器中删除该元素。

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

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