堆排序

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)

稳定性:不稳定

 

 

注意:此排序方法不适用于个数少的序列,因为初始构建堆需要时间

 

以上是关于堆排序的主要内容,如果未能解决你的问题,请参考以下文章

选择排序(简单选择排序堆排序的算法思想及代码实现)

排序--08---堆排序

python代码实现堆排序

算法-java代码实现堆排序

一文带你了解堆排序

堆排序