本文包括堆排序的代碼、例子(圖示)、時間復雜度分析
#define MAXSIZE 10000 /*全局變量,需要排序的數組*/ long long int num[MAXSIZE]; /*對非葉子結點和它的孩子結點進行調整,使其重新成為大根堆,用於堆排序*/ void NodeSort(long long int node,long long int len) { long long int left = node * 2 + 1, right = left + 1, max_node = left; while (left < len) { if (right < len && num[left] < num[right]) max_node = right; if (num[node] < num[max_node]) { swap(node, max_node); node = max_node; left = node * 2 + 1; right = left + 1; max_node = left; } else return; } } /*堆排序*/ void HeapSort(long long int len) { while (len != 0) { for (long long int i = len; i > 0; i -= 2)//將非葉子結點依次進行調整,保證每次for循環結束之后都是大根堆 NodeSort((i - 1) / 2, len); swap(len - 1, 0); //首尾元素交換 len--;//對除了最后一個元素外的數組繼續進行排序 } }
之后按照上述的調整堆的方式,不斷進行調整,直到堆只剩下根節點的時候,數組有序
堆排序分為兩步,即初始化堆、調整堆。
兩個步驟都要調用一個調整結點順序的函數NodeSort,以大根堆為例,操作為:
1:如果父親結點num[a]和它的兩個孩子結點num[2a+1], num[2a+2]滿足um[a] > max{num[2a+1], num[2a+2]},那么返回;
2:如果不滿足堆的性質,那么將父親結點num[a]和較大孩子結點max{num[2a+1], num[2a+2]}交換,
3:將原來較大的孩子結點作為父親結點,重復上述操作,直到孩子結點是葉子結點為止
初始化堆的時間復雜度分析
初始化堆的時候,對於每個非葉子結點,都要調用上述函數,將它與它的孩子結點進行比較和交換,順序是從后向前。
以操作2作為基本操作,對每一層都完全鋪滿的堆進行分析,
設元素個數為n,則堆的高度k=log(n+1)≈log n,非葉子結點的個數為2^(k-1)-1
假設每個非葉子結點都需要進行調整,則第i層的非葉子結點需要的操作次數為k-i,
第i層共有2^(i-1)個結點,則第i層的所有結點所做的操作為k*2^(i-1)- i*2^(i-1),
共k-1層非葉子結點,總的操作次數為
化簡可得,上式=2^k-k+1,將k=log(n+1)≈log n代入,得n - log n +1,
所以,初始化堆的復雜度為O(n)
調整堆的時間復雜度分析
調整堆的復雜度計算和初始化堆差不多,
假設根節點和排在最后的序號為m的葉子結點交換,並進行調整,那么調整的操作次數 = 原來m結點所在的層數 = 堆的高度(因為m結點在堆的最后)= log m
共n個結點,調整的總操作次數為
化簡可得,上式=log (n-1)! ≈ n*log n
所以,調整堆的復雜度為O(n*log n)
所以,總體復雜度為O(n*log n)