堆排序
Posted jpzhu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆排序相关的知识,希望对你有一定的参考价值。
概念
分为大顶堆和小顶堆,是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以用到上一次的排序结果,所以不像其他一般的排序方法一样,每次都要进行n-1次的比较,复杂度为O(nlogn)。
完全二叉树的性质
将堆的内容填入一个一维数组,这样通过下标就能计算出每个结点的父子节点,编号顺序从0开始,从左往右,从上至下层次遍历。a[10] = {2,8,5,10,9,12,7,14,15,13}
若一个结点的下标为k,那么它的父结点为(k-1)/2,其子节点为2k+1和2k+2
例:数字为10的节点的下标为3,父结点为1号:8,子节点为7号和8号:14,15
流程
1)利用给定数组创建一个堆H[0..n-1],输出堆顶元素
2)以最后一个元素代替堆顶,调整成堆,输出堆顶元素
3)把堆的尺寸缩小1
4) 重复步骤2,直到堆的尺寸为1
先构造一个大顶堆,移除最大元素(根节点),将最大元素与最小元素替换,重新构造一个大顶堆,循环移除
实现代码
1 void HeapBuild(vector<int> &nums, int root, int length) 2 { 3 int lchild = root * 2 + 1; 4 if (lchild < length)//左子结点下标不能超出数组的长度 5 { 6 int flag = lchild;//flag保存左右节点中最大值的下标 7 int rchild = lchild + 1; 8 if (rchild < length && nums[rchild] > nums[flag]) 9 flag = rchild;//找出左右子结点中的最大值 10 11 if (nums[root] < nums[flag]) 12 { 13 swap(nums[root], nums[flag]); 14 HeapBuild(nums, flag, length);//从此次最大子节点的那个位置开始递归建堆 15 } 16 } 17 } 18 19 void HeapSort(vector<int> &nums) 20 { 21 int len = nums.size(); 22 for (int i = len / 2; i >= 0; i--)//从最后一个非叶子节点的父节点开始建堆 23 { 24 HeapBuild(nums, i, len); 25 } 26 27 for (int j = len - 1; j > 0; j--) 28 { 29 swap(nums[0], nums[j]);//交换首尾元素,将最大值交换到数组的最后位置保存 30 HeapBuild(nums, 0, j);//去除最后位置的元素重新建堆,此处j表示数组的长度,最后一个位置下标变为len-2 31 } 32 }
性能
最差时间复杂度O(n log n)
最优时间复杂度O(n log n)
平均时间复杂度O(n log n)
最差空间复杂度O(n)
稳定性:不稳定
注意:此排序方法不适用于个数少的序列,因为初始构建堆需要时间
以上是关于堆排序的主要内容,如果未能解决你的问题,请参考以下文章