排序——堆排序-大根堆(大頂堆)
1.小根堆
若根節點存在左子女則根節點的值小於左子女的值;若根節點存在右子女則根節點的值小於右子女的值。
2.大根堆
若根節點存在左子女則根節點的值大於左子女的值;若根節點存在右子女則根節點的值大於右子女的值。
3.結論
(1)堆是一棵完全二叉樹(如果公有h層,那麼1~h-1層均滿,在h層連續缺失若干個右葉子)。
(2)小根堆的根節點的值是最小值,大根堆的根節點的值是最大值。
(3)堆適合於採用順序儲存。
4.堆的插入演算法
將乙個資料元素插入到堆中,使之依然成為乙個堆。
演算法描述:先將結點插入到堆的尾部,再將該結點逐層向上調整,直到依然構成乙個堆,調整方法是看每個子樹是否符合大(小)根堆的特點,不符合的話則調整葉子和根的位置。
5.堆的刪除演算法
堆在刪除元素時,只可以刪除根節點。
演算法描述:將根節點刪除後用堆尾結點進行填補,調整二叉樹,使之依然成為乙個堆。
6.堆排序(大根堆,小根堆類似)
其基本思想為(大根堆):
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]同該區間的最後乙個記錄交換,然後將新的無序區調整為新的堆。
因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆事實上也是調整堆的過程,只不過構造初始堆是對所有的非葉節點都進行調整。
從上述過程可知,堆排序其實也是一種選擇排序,是一種樹形選擇排序。只不過直接選擇排序中,為了從r[1...n]中選擇最大記錄,需比較n-1次,然後從r[1...n-2]中選擇最大記錄需比較n-2次。事實上這n-2次比較中有很多已經在前面的n-1次比較中已經做過,而樹形選擇排序恰好利用樹形的特點儲存了部分前面的比較結果,因此可以減少比較次數。對於n個關鍵字序列,最壞情況下每個節點需比較log2(n)次,因此其最壞情況下時間複雜度為nlog2(n)。堆排序為不穩定排序,不適合記錄較少的排序。
關於log2(n)的理解:根據堆排序的過程,每次將大根堆根節點的值跟最後乙個葉子的值進行交換,那如果最後的葉子結點正好是最小的數,那麼這個葉子結點就會一層層的被放到子樹最終放到葉子結點的位子(不是前面的葉子結點的位置了),這樣的話這個葉子結點經過的層數就剛好為log2(n)。然而其他沒有交換的二叉樹的分支,因為以前都是大根堆,所以大根堆的性質還是沒有變化,這一點對理解程式至關重要。
c語言程式如下:
#include /*注意:這個函式只會在調整被交換的位置為大根堆,未交換的分支不會處理,
所以不能將乙個非大根堆二叉樹的根結點傳遞過來讓這個函式將其處理為大根堆*/
void heap_ajust(int *a, int i, int size) /*a為堆儲存陣列,size為堆的大小*/
if(rchild<=size && a[rchild]>a[max])
if(max != i)
}
}
void build_bheap(int *a, int size) /*建立大根堆*/
}
void heap_sort(int *a, int size) /*堆排序*/
}
int main(int argc, charchar *argv)
; int size = sizeof(a)/sizeof(int) -1;
int i;
printf("size = %d\n", size);
heap_sort(a, size);
printf("sort over:"); //整理完畢
for(i=1;i <= size; i++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
int size = sizeof(a)/sizeof(int) -1; ①
算出int陣列a的位元組總長度,sizeof(int)指示出當前系統int的長度
1.在16位int平台下是2;
2.在32位int平台下是4;
3.在64位int平台下是8。
①處的語句將算出int a陣列一共有多少個位元組
輸出結果:
原文:
堆疊排序演算法
堆排序 維護的二叉樹是一顆完全二叉樹,大頂堆用來公升序排序,要求父節點大於等於左右子節點。而小丁堆用來降序排序,要求父節點小於等於左右子節點。堆排序 如果按公升序排序,就維護最大堆,降序就維護最小堆 這裡我們按公升序講 每次把最大元素放在堆頂,然後交換陣列的頭尾兩個元素,這樣陣列的最後乙個 元素就是...
排序演算法之排序
private static void insertsort int ints 時間複雜度 o n 2 空間複雜度 o 1 private static void mergesort int ints,int left,int right private static void merge int ...
排序演算法 排序演算法之選擇排序
最近在學習排序演算法,就排序演算法中的四大經典排序 氣泡排序 快速排序 選擇排序 插入排序。會出一系列的講解排序演算法的部落格。今天繼快速排序之後整理一下選擇排序。選擇排序,就是從一列未排序的陣列中先選出最小 最大 的數,放在陣列的第一位,第一位原來的數字放在最小的原來的位置,再選出第二小的數,放在...