堆與堆排序

2021-06-23 07:15:18 字數 2246 閱讀 8106

堆的儲存:

一般都用陣列來表示堆,i結點的父結點下標就為(i – 1) / 2。它的左右子結點下標分別為2 * i + 1和2 * i + 2。如第0個結點左右子結點下標分別為1和2。

堆排序的思想:

利用大頂堆(小頂堆)堆頂記錄的是最大關鍵字(最小關鍵字)這一特性,使得每次從無序中選擇最大記錄(最小記錄)變得簡單。

其基本思想為(大頂堆):

1)將初始待排序關鍵字序列(r1,r2....rn)構建成大頂堆,此堆為初始的無序區;

2)將堆頂元素r[1]與最後乙個元素r[n]交換,此時得到新的無序區(r1,r2,......rn-1)和新的有序區(rn),且滿足r[1,2...n-1]<=r[n]; 

3)由於交換後新的堆頂r[1]可能違反堆的性質,因此需要對當前無序區(r1,r2,......rn-1)調整為新堆,然後再次將r[1]與無序區最後乙個元素交換,得到新的無序區(r1,r2....rn-2)和新的有序區(rn-1,rn)。不斷重複此過程直到有序區的元素個數為n-1,則整個排序過程完成。

操作過程如下:

1)初始化堆:將r[1..n]構造為堆;

2)將當前無序區的堆頂元素r[1]同該區間的最後乙個記錄交換,然後將新的無序區調整為新的堆。

因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。

下面舉例說明:

給定乙個整形陣列a=,對其進行堆排序。

首先根據該陣列元素構建乙個完全二叉樹,得到

然後需要構造初始堆,則從最後乙個非葉節點開始調整,調整過程如下:

即每次調整都是從父節點、左孩子節點、右孩子節點三者中選擇最大者跟父節點進行交換(交換之後可能造成被交換的孩子節點不滿足堆的性質,因此每次交換之後要重新對被交換的孩子節點進行調整)。有了初始堆之後就可以進行排序了。

這樣整個區間便已經有序了。

從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從r[1...n]中選擇最大記錄,需比較n-1次,然後從r[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間複雜度為nlogn。堆排序為不穩定排序,不適合記錄較少的排序。

#include

#include

using namespace std;

void heapadjust(int *a,int i,int size)

if(rchild < size&&a[rchild] > a[max])

if(max != i)}}

void buildheap(int *a,int size)

}void heapsort(int *a,int size)

}int main()

;int size = 6;

heapsort(a,size);

for(int i = 1;i <= sizeof(a)/sizeof(a[0]);i++)

{cout<

堆與堆排序

二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足二個特性 1 父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值。2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 當父結點的鍵值總是大於或等於任何乙個子節點的鍵值時為最大堆。當父結點的鍵值總是小於或等於任何乙個子節點的鍵值時...

堆與堆排序

堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。堆排序是就地排序,輔助空間為o 1 它是不穩定的排序方法。排序的穩定性是指如果在排序的序列中,存在前後相同的兩個元素的話,排序前 和排序後他們的相對位置不發生變化 先說說什麼是堆,堆通常是乙個可以被看做一棵樹的陣列物...

堆與堆排序

堆排序與快速排序,歸併排序一樣都是時間複雜度為o n logn 的幾種常見排序方法。學習堆排序前,先講解下什麼是資料結構中的二叉堆。二叉堆是完全二叉樹或者是近似完全二叉樹。二叉堆滿足二個特性 1 父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值。2 每個結點的左子樹和右子樹都是乙個二叉堆...