排序算法 | 堆排序,算法的图解、实现、复杂度和稳定性分析

  • 今天讲解一下堆排序的原理以及实现、复杂度和稳定性分析

在这里插入图片描述


1 堆的定义

堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

定义:
n个关键字序列L[1…n]称为堆,当且仅当该序列满足:

① L(i)>=L(2i) 且 L(i)>=L(2i+1)或

② L(i)<=L(2i) 且 L(i)<=L(2i+1) (1≤isln/2])

可以将该一维数组视为一棵完全二叉树

这里是引用

大根堆:满足条件① 的堆称为大根堆(大顶堆),大根堆的最大元素存放在结点,且其任一非根结点的值小于等于其双亲结点值

在这里插入图片描述

对于堆中的元素编号,其实也是逻辑结构映射到数组的一个过程;

小根堆:满足条件2的堆称为小根堆(小顶堆),小根堆的定义刚好相反,结点是最小元素

这里是引用

2 堆排序的思路

首先将存放在L[1…n]中的n个元素建成初始堆,由于堆本身的特点(以大顶堆为例),堆顶元素就是最大值。
输出堆顶元素后,通常将堆底元素送入堆顶,堆被破坏,将堆顶元素向下调整使其继续保持大顶堆的性质,再输出堆顶元素。如此重复。

  • 根据数组构建一个完全二叉树
  • 从最后一个非叶节点开始调整,使得子树成为堆
  • 如此重复,直至满足堆的定义

值得注意的是:

大根堆排序结果为升序

小根堆排序结果为降序

这是一个常见的误区!

这是因为:堆使用的时候都是每次把堆顶的元素干掉留下堆内部的元素做成Top N

如果你要找100000中的 TOP100最大的,你用小根堆

如果你要找100000中的 TOP100最小的,你用大根堆

3 代码实现

void BuildMaxHeap(int *arr,int len)
{
	// 建立初始大根堆 
	for(int i = (len-1)/2; i >= 0; i--)
	{
		HeapAdjust(arr,i,len);
	}
}

// 子树调整 
void HeapAdjust(int *arr,int k,int len)
{
	int temp = arr[k]; // 暂存根节点 
	
	for(int i = k*2+1;i < len;i = i*2+1)
	{
		if (i < len-1 && arr[i] < arr[i+1])
			i++;
		if (temp >= arr[i])
			break; // 筛选结束 
		else {
			arr[k] = arr[i];
			k = i; // 继续向下筛选 
		}
	}
	arr[k] = temp ; // 筛选的值放入最终位置 
}

void HeapSort(int *arr,int len)
{
	BuildMaxHeap(arr,len);
	for(int i = len-1;i > 0;i--)
	{	
		arr[0] = arr[0] ^ arr[i];	
		arr[i] = arr[0] ^ arr[i]; 
		arr[0] = arr[0] ^ arr[i];
		HeapAdjust(arr,0,i);
	}
}

4 堆的输出(删除操作)

堆中根结点的值肯定是最值,不是最大就是最小,往往需要使用到。

即每次都删除第0个数据(根结点)

那么堆中输出根节点之后如何保证堆原有的特性呢?

删除之后,打破了原有规律,需要调整!

  • 删除根结点

  • 最后一个数据的值赋给根结点

  • 然后再从根结点开始进行一次从上向下的调整

在这里插入图片描述
在这里插入图片描述

5 堆的插入操作

  • 对堆进行插入操作时,先将新结点放在堆的末端

  • 随后再向上执行调整操作
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

6 堆排序的特点

堆排序适合关键字较多的情况(如n>1000)
不适合关键字较少的情况
大根堆排序结果为升序
小根堆排序结果为降序

例如,在1千万个数中选出前100个最大值?
首先使用一个大小为100的数组,读入前100个数,建立小顶堆,而后依次读入余下的数,若小于堆顶则舍弃,否则用该数取代堆顶并重新调整堆,待数据读取完毕,堆中100个数即为所求。

7 性能分析

【空间复杂度】:仅使用常数个辅助单元,空间复杂度为 O(1)

【时间复杂度】:建堆时间为 O(n),之后有n-1次向下调整操作,每次调整的时间复杂度为 O(h) h表示树高

故在最好、最坏和平均情况下,堆排序的时间复杂度为 O(nlog2n)

【稳定性】:进行筛选时,有可能把后面相同关键字的元素调整到前面,所以堆排序算法是一种不稳定的排序方法

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 35
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值