算法思想:
借助最大堆的性质,堆的根节点是最大的节点,每次迭代将根节点从堆中摘除,用最末一个叶子节点替代原先的根节点,此时新生成的树不具有堆的性质,所以要对树的结构进行调整,让新树的根下降到较低的层次(最大堆的根节点不小于它的子节点),以此来重新构造一个最大堆。
算法步骤:
1、首先建立最大堆
2、排序思想是每次迭代都把根元素与最后一个元素交换,同时剔除根元素(heapSize - 1),再对交换上来的根进行调整,保持堆的性质。
1 // 最大堆调整 2 // i为待调整的根节点 3 void maxHeapify(int *A, int i, int size) { 4 // 根编号为0的左右孩子下标 5 int l = 2 * i + 1; 6 int r = 2 * i + 2; 7 // 首先默认根节点为最大 8 int largest = i; 9 if (l < size && A[l] > A[i]) { 10 largest = l; 11 } 12 if (r < size && A[r] > A[largest]) { 13 largest = r; 14 } 15 if (largest != i) { 16 mySwap(A[largest], A[i]); 17 // 递归调整根为largest的子树 18 maxHeapify(A, largest, size); 19 } 20 } 21 22 // 建最大堆 23 void buildMaxHeap(int *A, int size) { 24 // size/2至size-1为叶子节点 25 // 对非叶子节点进行调整 26 for (int i = (size - 1) / 2; i >= 0; i--) { 27 maxHeapify(A, i, size); 28 } 29 } 30 31 void heapSort(int *A, int size) { 32 buildMaxHeap(A, size); 33 for (int i = size - 1; i >= 1; i--) { 34 // 将根元素交换到后面 35 mySwap(A[0], A[i]); 36 size -= 1; 37 // 交换后堆的性质可能没有保持,对新的根节点进行调整 38 maxHeapify(A, 0, size); 39 } 40 }
算法分析:
buildMaxHeap()建堆的复杂度算法导论P88上的推算为O(n),即线性时间。堆调整maxHeapify()的复杂度为O(logn),所以heapSort()的复杂度为O(n + n*logn)=O(logn)。