原文

簡介

本文簡要介紹數據結構  的概念並提供了實現源碼: CHeapTree類。CHeapTree類的實現是基於一個自動增長的數組。

 

什麼是堆

堆是一種特殊的二叉完全樹。堆的一個主要特點是它以一定的偏序(a partial order)來保存所有節點[譯者注:此處的偏序是指不完全的排序,堆只需要滿足父節點大於兩個子節點,而子節點之間沒有要求]。作爲一顆完全樹,一層中的節點是從左到右填滿的。如果一個節點沒有左兒子,那麼它一定沒有右兒子。並且在第h層中如果存在節點,那麼第h-1層必須是填滿的。

 

以下是堆的正式定義(摘自Computer Algorithms by S. Baase and A. Van Gelder):

 

一個二叉樹V是一個堆,當且僅當它滿足以下條件:

  • V從根節點至h-1層是完全樹
  • 所有的葉子節點只存在於h與h-1層上
  • 所有到達h層葉子節點的路勁都在到達h-1層葉子節點路徑的左側

堆有兩種:最大堆和最小堆。最小堆中每個節點的優先級小於或者等於它的子節點;最大堆則相反,每個節點的優先級都大於或者等於它的子節點。

 

圖示最大堆(左)和最小堆(右):

 

 

實現細節

CHeapTree類通過一個數組,從上至下、從左至右地保存樹中的節點來實現堆。因此,上述圖示中的最大堆就可以表示爲10,9,8,6,1,5。在這種表示方式中,第j個節點的子節點和父節點的表達如下(假設起始索引值是0):

  • 左子節點 = j*2-1
  • 右子節點 = j*2 = 左子節點+1
  • 父節點     = (j-1)/ 2

如果索引值越界,則該節點不存在。

 

代價

建堆過程中的比較次數:O(n)

刪除堆的比較次數:2*n*lg(n)[譯者注:刪除一個元素的比較次數爲2*lg[n],所以要刪除所有元素需要n*2*lg(n)]

堆排序的平均時間複雜度是n*lg(n)

 

CHeapTree declaration(實現細節省略)

template <class TID, class TDATA>
class CHeapTree
{
    struct _NODE {
        TID id;
        TDATA data;
    };
    _NODE *m_data;

public:
    CHeapTree(int nInitMax = 100);
    ~CHeapTree();

    bool IsEmpty() const { return m_nSize == 0; }
    int GetSize() const { return m_nSize; }

    void Insert(const TID &id, const TDATA &data);
    bool RemoveTop();
    bool RemoveAll();

    bool GetTopID(TID *pid) const;
    bool GetTopData(TDATA *pdata) const;
    bool GetData(const TID &id, TDATA *pdata) const;

    bool ResetData(const TID &id, const TDATA &data);

private:
    void _ReformatHeap(int iRoot);
};

CHeapTree類實現了堆的基本操作。每個節點中排序基準的數據類型是TDATA類型。所以,如果TDATA是一種用戶自定義的數據類型,需要實現<,=,>的運算符重載,即該類型的比較邏輯需由用戶給出。TID是用來唯一表示一個節點的值。

默認情況下,CHeapTree是一個最小堆即TDATA中最小值具有最高的排序優先權。如果需要一個最大堆,將TDATA類型的比較運算符的邏輯倒置即可。

 

如何使用

使用該CHeapTree類很簡單,可以如下所示:

// int=id, float=priority [as less as better]

CHeapTree<int, float> h;
h.Insert(0, 0.1f);
h.Insert(1, 0.2f);
h.Insert(2, 0.15f);
h.Insert(3, 0.3f);
h.Insert(4, 0.21f);

h.ResetData(3, 0.19f);
// The order should be [0, 2, 3, 1, 4]


while (!h.IsEmpty()) {
    int top;
    h.GetTopID(&top); 
    float data;
    h.GetTopData(&data); 
    cout << "(" << top << " : " << data << ")/n";
    h.RemoveTop();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章