本章開始介紹了堆的基本概念,然後引入最大堆和最小堆的概念。全章採用最大堆來介紹堆的操作,兩個重要的操作是調整最大堆和建立最大堆,接著著兩個操作引進了堆排序,最後介紹了採用堆實現優先順序佇列。
(二叉)堆資料結構是一種陣列物件,它可以被視為一棵完全二叉樹。除了最底層外,該樹是完全充滿的,而且是從左到右填充的。樹中每個節點與陣列中的存放該節點值的那個元素對應。堆與完全二叉樹的對應關係如下圖所示:
表示堆的陣列a包括兩個屬性: a.length是陣列中的元素個數,a.heap-size是存放在中的堆的元素個數。通常給定節點i,可以根據其在陣列中的位置求出該節點的父親節點、左右孩子節點。輸的根節點是a[1],對於乙個給定結點的下標i,所有可到:
根據節點數值滿足的條件,可以將分為最大堆和最小堆。最大堆的特性是:除了根節點以外的每個節點i,有a[parent(i)] >= a[i],最小堆的特性是:除了根節點以外的每個節點i,有a[parent(i)] >=a[i]。
把堆看成乙個棵樹,有如下的特性:
(1)含有n個元素的堆的高度是lgn。
(2)當用陣列表示儲存了n個元素的堆時,葉子節點的下標是n/2+1,n/2+2,……,n。
(3)在最大堆中,最大元素該子樹的根上;在最小堆中,最小元素在該子樹的根上。
堆的關鍵操作過程是如何維持堆的特有性質,給定乙個節點i,要保證以i為根的子樹滿足堆性質。書中以最大堆作為例子進行講解,並給出了遞迴形式的保持最大堆性的操作過程max-heapify。先從看乙個例子,操作過程如下圖所示:
從圖中可以看出,在節點i=2時,不滿足最大堆的要求,需要進行調整,選擇節點2的左右孩子中最大乙個進行交換,然後檢查交換後的節點i=4是否滿足最大堆的要求,從圖看出不滿足,接著進行調整,直到沒有交換為止。書中給出了遞迴形式的偽**:
max-heapify(a,i)
1 l = left(i)
2 r = right(i)
3 if l<=a.heap-size and a[l] > a[i]
4 largest = l
5 else largest = i
6 if r <= a.heap-size and a[r] > a[largest]
7 largest = r
8 if largest != i
9 exchange a[i] with a[largest]
10 max-heapify(a, largest)
建立最大堆的過程是自底向上地呼叫最大堆調整程式將乙個陣列a[1.....n]變成乙個最大堆。將陣列視為一顆完全二叉樹,從其最後乙個非葉子節點(n/2)開始調整。調整過程如下圖所示:
書中給出了建立堆的為**
build-max-heap(a)
1 a.heap-size = a.length
2 for i = a.length/2 downto 1
3 max-heapify(a, i)
堆排序演算法過程為:先呼叫建立堆函式將輸入陣列a[1...n]造成乙個最大堆,使得最大的值存放在陣列第乙個位置a[1],然後用陣列最後乙個位置元素與第乙個位置進行交換,並將堆的大小減少1,並呼叫最大堆調整函式從第乙個位置調整最大堆。給出堆陣列a=進行堆排序簡單的過程如下:
(1)建立最大堆,陣列第乙個元素最大,執行後結果下圖:
(2)進行迴圈,從length(a)到2,並不斷的調整最大堆,給出乙個簡單過程如下:
書中給出了對排序為**
heapsort(a)
1 build-max-heap(a)
2 for i = a.length downto 2
3 exchange a[1] with a[i]
4 a.heap-size = a.heap-size-1
5 max-heapify(a, 1)
結合上面的調整堆和建立堆 的過程,寫個簡單測試程式連續堆排序,程式如下所示:
/*
*created by rogerking
*email:[email protected]
*/#include #include using namespace std;
int heap_size,i;
int parent(int i)
//查詢堆中節點父母
int left(int i)
//查詢堆中節點左孩子(因為程式下標是從0開始的)
int right(int i)
//查詢堆中節點右孩子
void max_heapify(int a,int i,int n)
}void bulid_max_heap(int a,int n)
void heapsort(int a,int n) }
void display(int a,int n)
return 0;
}
堆排序演算法時間複雜度:調整堆過程滿足遞迴式t(n)<=t(2n/3)+θ(1),有master定義可以知道t(n) = o(lgn),堆排序過程中執行乙個迴圈,呼叫最大堆調整函式,總的時間複雜度為o(nlgn)。 演算法導論 第六章 堆排序
二叉 堆資料結構是一種陣列物件,如下圖所知,他可以被視為一顆完全二叉樹。其有如下性質 1 對於i節點 i表示下標 其父節點為li 2 左孩子節點為2i,右孩子節點為2i 1 2 最大堆滿足 a parent i a i 最小堆滿足 a parent i a i 3 堆的高度為 lgn 4 子陣列元素...
演算法導論第六章 堆排序
堆排序 主要是二叉堆,是乙個陣列,可以近似看作是一棵完全二叉樹。最壞情況執行時間為 n log n 主要性質 1.對於任意乙個下標index,書上寫的是左子女的下標為 2 index,右子女為 2 index 1 但是在實際程式設計中,下標是從0開始的,所以下標的變化應該為 左子女為2 index ...
演算法導論第六章堆排序6 2
6.2 1 第一遍交換10和3 第二遍交換10和9 6.2 2 6.2 2 min heapify a,i 1 l left i 2 r right i 3 if l heap size a and a l a i 4 then smallest l 5 else smallest i 6 if r...