標籤:全域 i+1 堆排序 strong 演算法 子節點 選擇 完全 記錄
完全二叉樹是效率很高的資料結構,堆是一種完全二叉樹或者近似完全二叉樹,所以效率同樣極高。目前十分常用的排序演算法、Dijkstra演算法、Prim演算法等都要用堆才能最佳化。
堆排序是一種選擇排序演算法,與原序列的初始排列次序無關,即最好、最壞和一般情況排序的時間複雜度不變,均為O(nlgn)。而且,堆排序只需要一個記錄記錄元素大小的輔助空間(供交換使用),故空間複雜度為O(1)。正由於堆排序不僅時間複雜度小,而且空間複雜度O(1)也是最小,所以是用於排序的最佳選擇。
堆的定義
n個元素序列 { k0,k1,..., kn } 若且唯若滿足下列條件之一時,稱之為堆(其中 i = 0, 1, ..., n/2 向下取整)。
- ki <= k2i+1 且 ki <= k2i+2(最小堆)
- ki >= k2i+1 且 ki >= k2i+2(最大堆)
堆排序實現
方法1:
利用最小堆性質實現堆排序
/*交換數組中兩個元素的值*/void swap(int *arr, int a, int b){ int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp;}/*(小根)堆調整*/void minHeapify(int *arr, int heapSize, int curNode){ /*找出當前節點和其左右節點三者的最小值*/ int minNode = curNode; int left = curNode * 2 + 1; int right = curNode * 2 + 2; if(left < heapSize && arr[left] < arr[minNode]) //左孩子存在且較小 minNode = left; if(right < heapSize && arr[right] < arr[minNode]) //右孩子存在且較小 minNode = right; if(minNode != curNode) //當前節點不是最小則需要交換 { swap(arr, minNode, curNode); minHeapify(arr, heapSize, minNode); //子節點需重新調整 }}/*構建堆*/void createHeap(int *arr, int heapSize){ for(int i = heapSize/2 - 1; i >= 0; i--) //從最後一個非分葉節點開始 { minHeapify(arr, heapSize, i); }}/*(最小)堆排序*思想:*1、構建最小堆*2、從最後一個元素開始只第二個元素將依次與首元素交換*3、全域調整堆
*上面步驟2和步驟3將所有元素都與首元素交換,然後進行全域範圍的堆調整,利用最小堆的性質實現將所有元素按從小到大的方式排序*/void heapSort(int *arr, int length){ createHeap(arr, length); //構建堆 for(int i = length-1; i > 0; i--) { swap(arr, 0, i); //與首元素交換 minHeapify(arr, length, 0); //調整堆 }}
方法2
利用最大堆性質實現堆排序
/*交換數組中兩個元素的值*/void swap(int *arr, int a, int b){ int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp;}/*(大根)堆調整*/void maxHeapify(int *arr, int heapSize, int curNode){ /*找出當前節點和其左右節點三者的最小值*/ int maxNode = curNode; int left = curNode * 2 + 1; int right = curNode * 2 + 2; if(left < heapSize && arr[left] > arr[maxNode]) //左孩子存在且較小 maxNode = left; if(right < heapSize && arr[right] > arr[maxNode]) //右孩子存在且較小 maxNode = right; if(maxNode != curNode) //當前節點不是最小則需要交換 { swap(arr, maxNode, curNode); maxHeapify(arr, heapSize, maxNode); //子節點需重新調整 }}/*構建堆*/void createHeap(int *arr, int heapSize){ for(int i = heapSize/2 - 1; i >= 0; i--) //從最後一個非分葉節點開始 { maxHeapify(arr, heapSize, i); }}/*(最大)堆排序*思想:*1、構建最大堆*2、從最後一個元素開始只第二個元素將依次與首元素交換*3、進行數組中當前元素前面的所有元素的局部調整堆*上面步驟2和步驟3將所有元素都與首元素交換,將局部範圍內的最大值沉到後面,然後進行當前元素前面所有元素的局部範圍內的堆調整*即在數組A中,當前元素索引為i,將A[i]與A[0]交換,將A[0,1,...,i]中最大的值放到A[i],然後進行A[0,1,...,i-1]堆調整,*將A[0,1,...,i-1]內的最大值放到A[0]中,待下一次交換使用,實現將局部的最大值依次沉到數組後面,完成排序*/void heapSort(int *arr, int length){ createHeap(arr, length); //構建堆 for(int i = length-1; i > 0; i--) { swap(arr, 0, i); //與首元素交換 maxHeapify(arr, i, 0); //調整堆 }}
考研資料結構筆記—堆排序