堆排序
1.建堆。n个数存放于数组里,下表从1到n。叶子下标则是:n/2+1, n/2+2...n。建堆的时候从最后一个非叶子节点到第一个节点,不断进行调整。
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <vector> using namespace std; void MaxHeapify(int maxHeap[], int n, int nowPos) { int left, right, largest; left = nowPos << 1; right = (nowPos<<1|1); largest = nowPos; if(left <= n && maxHeap[left] > maxHeap[nowPos]) largest = left; if(right <= n && maxHeap[right] > maxHeap[largest]) largest = right; if(largest != nowPos) { swap(maxHeap[nowPos], maxHeap[largest]); MaxHeapify(maxHeap, n, largest); } } void buildMaxHeap(int maxHeap[], int n) { for(int i = n/2; i >= 1; --i) MaxHeapify(maxHeap, n, i); } int main() { int maxHeap[50] = {0, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; buildMaxHeap(maxHeap, 10); return 0; }
2.堆排序。先用buildMaxHeap将输入的数组A[1...n]建成大顶堆。因为最大元素在A[1],交换A[1]和A[n]将数放入最终的位置,接着用MaxHeapify()调整A[1...n-1]建成大顶堆,不断重复这个过程。
#include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <vector> using namespace std; void MaxHeapify(int maxHeap[], int n, int nowPos) { int left, right, largest; left = nowPos << 1; right = (nowPos<<1|1); largest = nowPos; if(left <= n && maxHeap[left] > maxHeap[nowPos]) largest = left; if(right <= n && maxHeap[right] > maxHeap[largest]) largest = right; if(largest != nowPos) { swap(maxHeap[nowPos], maxHeap[largest]); MaxHeapify(maxHeap, n, largest); } } void buildMaxHeap(int maxHeap[], int n) { for(int i = n/2; i >= 1; --i) MaxHeapify(maxHeap, n, i); } void HeapSort(int maxHeap[], int n) { buildMaxHeap(maxHeap, 10); for(int i = n; i >= 2; --i) { swap(maxHeap[1], maxHeap[i]); MaxHeapify(maxHeap, i-1, 1); } } int main() { int maxHeap[50] = {0, 4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; HeapSort(maxHeap, 10); for(int i = 1; i <= 10; ++i) printf("%d ", maxHeap[i]); return 0; }
3.建堆效率。很容易会以为建堆的效率是nlogn,因为外层n的循环里还有个沿着树自上而下的调整。实际效率为o(n)。
假设一棵平衡二叉树的高度为h,则第一层的节点数为2^0,最后一层非叶子节点的节点数为2^(n-2)。最后一层非叶子节点要调整的深度为1,向上依次为2,3...n-1。
所以,建堆总的时间:
T=2^(h-2)*1 + 2^(h-3)*2 + ... + 2^1 * (h-2) + 1 * (h-1); (1)式 (1)*2可得
2*T=2^(h-1)*1 + 2^(h-2)*2 + ... + 2^2*(h-2) + 2*(h-1); (2)式 (2)-(1)得
2T-T = T = 2^(h-1) + 2^(h-2) + ...+ 2^1 - h + 1 = 2^h - h - 1;
又h = logn,所以T = n + logn + 1;故效率为o(n)。