繁体   English   中英

用堆构建优先级队列

[英]Building a priority queue with a heap

如果堆是基于数组的,并且提取了根,则我正在使用的代码应该重新组合节点,以便维护堆属性。

从我的理解来看,数组和堆并不完全相同,但是在代码中,构建堆似乎只是重新排列了数组,使其拥有堆属性。 这是创建堆的标准方法吗? 是否有必要填充另一个数组而不是仅仅更改它所基于的数组?

我很难理解这个概念,因为当我使用函数extract-max删除根时,除非我从数组中弹出元素,否则数组的大小将保持不变。 堆应该较小,但是所有发生的事情是,向上移动以替换根的节点在数组中用零表示,并且不将其删除。

如果我确实保留了结构,即堆基本上就是遵循堆属性的数组,那么如何删除不再属于堆的节点? 在我的代码中,打印数组时,此节点用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;
}

输出:

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 

所以。 我更改了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;
}

然后我擦除了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;
}

我得到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 

最初,我真的以为我可以在将最后一个元素的值记录到根之后弹出最后一个元素,然后重新组织堆,但是并没有合作。 因此,替代方法是在重组堆之后删除节点位置。

回到原始代码:

我意识到问题出在哪里。 我需要在使用变量而不是之后对数组进行索引之前减小堆大小。 然后,我可以按预期方式弹出最后一个元素。

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

您的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;
}

之后,您可以根据需要在std::deque上安全地使用pop_back()从容器中删除该元素。

暂无
暂无

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

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