簡體   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