簡體   English   中英

優先級隊列和堆之間的區別

[英]Difference between priority queue and a heap

似乎優先級隊列只是一個具有正常隊列操作(如插入、刪除、頂部等)的堆。這是解釋優先級隊列的正確方法嗎? 我知道您可以用不同的方式構建優先級隊列,但是如果我要從堆中構建優先級隊列,是否有必要創建一個優先級隊列 class 並給出構建堆和隊列操作的說明,或者真的不需要構建class?

我的意思是,如果我有一個 function 來構建堆和函數來執行插入和刪除等操作,我是否需要將所有這些函數放在 class 中,或者我可以通過在main中調用它們來使用指令。

我想我的問題是擁有一組函數是否等同於將它們存儲在一些 class 並通過 class 使用它們或僅使用函數本身。

下面是優先級隊列實現的所有方法。 這足以將其稱為實現還是我需要將其放入指定的優先級隊列 class 中?

#ifndef MAX_PRIORITYQ_H
#define MAX_PRIORITYQ_H
#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);
        //int j = max_heapify(A, largest, heapsize);
        //return j;
    }
    //return i;
}

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_maximum(std::deque<int> &A)
{
    return A[0];
}

int heap_extract_max(std::deque<int> &A, int heapsize)
{
    if(heapsize < 0)
        throw std::out_of_range("heap underflow");
    int max = A.front();
    //std::cout << "heapsize : " << heapsize << std::endl;
    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;
}

void heap_increase_key(std::deque<int> &A, int i, int key)
{
    if(key < A[i])
        std::cerr << "New key is smaller than current key" << std::endl;
    else {
        A[i] = key;
        while(i > 1 && A[parent(i)] < A[i]) {
            exchange(A, i, parent(i));
            i = parent(i);
        }
    }
}

void max_heap_insert(std::deque<int> &A, int key)
{
    int heapsize =  A.size();
    A[heapsize] = std::numeric_limits<int>::min();
    heap_increase_key(A, heapsize, key);
}

優先級隊列是一種抽象數據類型 它是描述特定接口和行為的速記方式,並沒有說明底層實現。

堆是一種數據結構 它是一種特殊的數據存儲方式的名稱,它使某些操作非常有效。

恰巧堆是實現優先級隊列的一個很好的數據結構,因為堆數據結構使高效的操作是優先級隊列接口需要的操作。

擁有一個完全符合您需要的接口的類(只是插入和彈出最大?)有其優勢。

  • 您可以稍后交換實現(例如列表而不是堆)。
  • 閱讀使用隊列的代碼的人不需要了解堆數據結構的更難的接口。

我想我的問題是擁有一組函數是否等同於將它們存儲在某個類中並通過類使用它們或僅使用函數本身。

如果您只考慮“我的程序的行為方式”,這幾乎是等效的。 但這並不等同於“我的程序有多容易被人類讀者理解”

術語優先級隊列是指用於對其元素的優先級進行排序的通用數據結構。 有多種方法可以實現這一點,例如各種有序樹結構(例如,展開樹工作得相當好)以及各種堆,例如 d 堆或斐波那契堆。 從概念上講,是一種樹結構,其中每個節點的權重不小於從該節點路由的子樹中任何節點的權重。

C++ 標准模板庫為堆(通常實現為二進制堆)提供了 make_heap、push_heap 和 pop_heap 算法,這些算法在任意隨機訪問迭代器上運行。 它將迭代器視為對數組的引用,並使用數組到堆的轉換。 它還提供了容器適配器priority_queue,它將這些設施包裝在一個類似容器的類中。 但是,沒有對減少/增加鍵操作的標准支持。

priority_queue 是指完全由可能對其執行的操作定義的抽象數據類型 因此,在 C++ STL 中, prioroty_queue序列適配器之一——基本容器的適配器(向量、列表和雙端隊列是基本的,因為它們不能在不損失效率的情況下相互構建),定義在<queue>頭文件 ( <bits/stl_queue.h>實際上就我而言)。 從它的定義可以看出,(如 Bjarne Stroustrup 所說):

容器適配器為容器提供受限接口。 特別是,適配器不提供迭代器; 它們旨在僅通過其專用接口使用

在我的實現中prioroty_queue被描述為

/**
   *  @brief  A standard container automatically sorting its contents.
   *
   *  @ingroup sequences
   *
   *  This is not a true container, but an @e adaptor.  It holds
   *  another container, and provides a wrapper interface to that
   *  container.  The wrapper is what enforces priority-based sorting 
   *  and %queue behavior.  Very few of the standard container/sequence
   *  interface requirements are met (e.g., iterators).
   *
   *  The second template parameter defines the type of the underlying
   *  sequence/container.  It defaults to std::vector, but it can be
   *  any type that supports @c front(), @c push_back, @c pop_back,
   *  and random-access iterators, such as std::deque or an
   *  appropriate user-defined type.
   *
   *  The third template parameter supplies the means of making
   *  priority comparisons.  It defaults to @c less<value_type> but
   *  can be anything defining a strict weak ordering.
   *
   *  Members not found in "normal" containers are @c container_type,
   *  which is a typedef for the second Sequence parameter, and @c
   *  push, @c pop, and @c top, which are standard %queue operations.
   *  @note No equality/comparison operators are provided for
   *  %priority_queue.
   *  @note Sorting of the elements takes place as they are added to,
   *  and removed from, the %priority_queue using the
   *  %priority_queue's member functions.  If you access the elements
   *  by other means, and change their data such that the sorting
   *  order would be different, the %priority_queue will not re-sort
   *  the elements for you.  (How could it know to do so?)

模板:

  template<typename _Tp, typename _Sequence = vector<_Tp>,
       typename _Compare  = less<typename _Sequence::value_type> >
    class priority_queue
    {

與此相反,描述了它的元素是如何被獲取和存儲在內存中的。 它是一個(基於樹的)數據結構,其他是數組、哈希表、結構、聯合、集合...,此外還滿足堆屬性:所有節點都是[大於或等於]或[小於或根據為堆定義的比較謂詞,等於]其每個子代。

所以在我的堆頭中我沒有找到堆容器,而是一組算法

  /**
   * @defgroup heap_algorithms Heap Algorithms
   * @ingroup sorting_algorithms
   */ 

像:

  • __is_heap_until
  • __is_heap
  • __push_heap
  • __adjust_heap
  • __pop_heap
  • make_heap
  • 排序堆

所有這些(不包括 __is_heap,評論為“這個函數是一個擴展,不是 C++ 標准的一部分”)描述為

   *  @ingroup heap_algorithms
   *
   *  This operation... (what it  does)

並不真地。 名稱中的“優先級”源於隊列中條目的優先級值,定義了它們……當然是:優先級。 然而,有很多方法可以實現這樣的 PQ。

優先級隊列是一種抽象數據結構,可以通過多種方式實現—— unsorted array,sorted array,heap 它就像一個接口,它給你堆的簽名:

class PriorityQueue {
   top() → element
   peek() → element
   insert(element, priority)
   remove(element)
   update(element, newPriority)
   size() → int
}

堆是優先級隊列的具體實現,它使用數組(它在概念上可以表示為一種特定類型的二叉樹)來保存元素和特定算法來強制執行不變量。 不變量是在數據結構的整個生命周期中始終成立的內部屬性。

這是優先隊列實現的性能比較:

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM