声明:本文参考了疯狂代码的文章,表示感谢,原文链接http://blog.csdn.net/jiqiren007/archive/2010/10/28/5972735.aspx /* * 堆排序 * 1) 建堆,建堆是不断调整的过程,从len/2处开始调整,直到第一个节点,len是堆中元素的个数 * 建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程O(h1) + O(h2) + O(hlen/2), 其中h表示节点的深度,len/2表示节点个数,这是一个求和的过程,结果是线性O(n) * 2) 调整堆,求出节点、左孩子、右孩子中的最大值,如果最大值不是根节点而是孩子节点,则需要与孩子 * 交换,然后再调用调整过程,这是一个递归过程,调整堆的过程时间复杂度与堆的深度有关,是logn的 * 操作,因为是沿着深度调整的。 * 3) 堆排序,堆排序是利用上面两个过程来进行的。首先构建堆,然后将根节点取出与最后一个元素进行交换, * 将前面len-1个继续进行堆调整堆过程,然后再将根节点取出,一直到所有节点都取出。 * 稳定性:不稳定 * 空间复杂度:O(1) * 时间复杂度:O(nlogn) 其中建堆的时间为O(n),调整堆的时间O(logn),需要调整n-1次,所以为nlogn * 适用情况:元素比较多的情况 */ #define Left(a) (((a)<<1)+1) //求左孩子 #define Right(a) (((a)<<1)+2) //求右孩子 /* * 调整堆 */ void AdjustHeap(int a[], int n, int pos) { if(n < 0 || pos < 0 || pos > n) { return; } int temp = 0; int large = pos; int left = Left(pos); int right = Right(pos); //求以上三个数中最大的 if(left < n && a[left] > a[pos]) { large = left; } if(right < n && a[right] > a[large]) { large = right; } if(large != pos) { //将根节点和最大的节点进行交换 temp = a[pos]; a[pos] = a[large]; a[large] = temp; //递归调整堆,沿着堆得深度进行,logn AdjustHeap(a, n, large); } } /* * 建堆 */ void CreateHeap(int a[], int n) { if(n < 0) { return; } int pos = (n-1) / 2;//下标从0开始 for(; pos >=0; pos--) { AdjustHeap(a, n, pos);//每次是lgh,h是节点的高度 } } /* * 堆排序 * 1)首先调用CreateHeap建堆,建堆后第一个元素就是最大或者最小的元素, * 将该元素与最后一个元素进行交换 * 2)调用AdjustHeap调整堆,堆得长度-1 */ void HeapSort(int a[], int n) { if(n < 0) { return; } int temp = a[0]; //建堆 CreateHeap(a, n); for(int i=0; i<n-1; i++) { temp = a[0]; a[0] = a[n-1-i]; a[n-1-i] = temp; AdjustHeap(a, n-i-1, 0); } } int main() { int a[] = {3, 8, 15, 7, 21, 6}; HeapSort(a, 6); for(int i=0; i<6; i++) { cout << a[i] << " "; } cout << endl; system("pause"); return 0; }