標籤:圖片 color 歸併排序 最大值 迭代 最小 很多 排序演算法 複雜度
一、堆的概念
所謂堆,它是一個數組,也能夠被看成一個近似的全然二叉樹。樹上每一個結點相應數組的一個元素。二元堆積分為二種:最大堆和最小堆。本文主要介紹最大堆,最小堆類似。最大堆的特點:對於隨意某個結點,該結點的值大於左孩子、右孩子的值,可是左右孩子的值沒有要求。
二、堆排序演算法
首先,按堆的定義將數組R[0..n]調整為堆(這個過程稱為建立初始堆),交換R[0]和R[n];
然後,將R[0..n-1]調整為堆,交換R[0]和R[n-1];
如此反覆,直到交換了R[0]和R[1]為止。
以上思想可歸納為兩個操作:
(1)根據初始數組去構造初始堆(構建一個完全二叉樹,保證所有的父結點都比它的孩子結點數值大)。
這裡可以利用完全二叉樹的結構,從最後一個非終端節點開始對子項目進行排序篩選。
(2)每次交換第一個和最後一個元素,輸出最後一個元素(最大值),然後把剩下元素重新調整為大根堆。
當輸出完最後一個元素後,這個數組已經是按照從小到大的順序排列了。
具體圖片我就不找了,網上很多。
三、演算法比較
堆排序演算法的時間複雜度是O(nlgn),比插入排序要好,跟歸併排序相同,但是與歸併排序不一樣的地方在於,堆排序不需要額外的儲存空間,或者說,只需要常數個額外的儲存空間,屬於內排序演算法。
#include <stdio.h>#define N 1000#define INF 999999999int h[N];//調整堆(迭代法)//n:規模 i:二叉子堆的堆頂voidheapAdjust(int n, int par){ int tmp, pos, lc, rc; while (par <= n/2) { tmp = h[par]; //記錄父母結點索引值 lc = par<<1; rc = lc+1; pos = par; //父母結點至多更新2次 if (h[par] < h[lc]) { h[par] = h[lc]; pos = lc; } if (rc <= n && h[par] < h[rc]) { h[par] = h[rc]; pos = rc; } if (pos == par) //無更新即無需調整 break; else h[pos] = tmp; par = pos; //假設這個位置的結點是“父母結點” }}//建立堆//規模為n的堆,對其父母結點,自底向上自右向左地調整堆voidcreateHeap(int n){ int i; for (i = n/2; i != 0; i--) { heapAdjust(n, i); }}voidheapSort(int n){ int ntimes = n; while (ntimes--) { printf("%d\n", h[1]); h[1] = h[n]; h[n--] = 0; //堆清零 heapAdjust(n, 1); }}intmain(void){ int n, i; scanf("%d", &n); h[0] = INF; for (i = 1; i != n+1; i++) { scanf("%d", &h[i]); } createHeap(n); heapSort(n); return 0;}/* 參考測試資料6342 31 52 626 12 1241043 525 14 21 52 3 52 45 319 15155*/
堆排序(C語言實現)