数据结构|排序算法(三)堆排序

二、堆排序

堆是一种特殊的完全二叉树,分为大根堆和小根堆。

大根堆的每个节点的值都大于或等于其左右子节点的值,小根堆则相反,每个节点的值都小于或等于其左右子节点的值。(大根堆小根堆只看父子关系)

堆排序的基本思想是将待排序的序列构建成一个堆,然后依次取出堆顶元素并调整堆,直到整个序列有序。

1.算法思想

建堆:将给定的数组构建成一个大根堆(或小根堆)。从最后一个非叶子节点开始,依次向上调整每个节点,使其满足堆的性质。

交换元素:将堆顶元素与堆的最后一个元素交换位置,此时堆顶元素是当前堆中的最大(或最小)值,将其取出,放到已排序序列的末尾。

调整堆:交换元素后,堆的性质可能被破坏,需要对剩余的元素重新调整堆,使其再次满足堆的性质。重复步骤 2 和 3,直到堆中只剩下一个元素,此时整个数组已经有序。

1->调整成大根堆

(1)从最后一棵子树开始,从后往前调整

(2)每次调整,从上往下

(3)整体调整成大根堆

具体调整:

定义一个临时变量tmp,把根放到tmp里,找左右孩子的最大值,和tmp比较,如果比tmp大,则放到根的位置,继续递归比较新的左右孩子的最大值

调整顺序:
调整子树:调整完成:

2->根和待排序的最后一个交换

根是最大的,交换后则视作有序

3->再次调整成大根堆

2.代码实现

复制代码
//堆排序
 
void HeapAdjust(int* arr, int start, int end)
{
	int tmp = arr[start];
	for (int i = 2 * start + 1; i <= end;i=2*i+1)//从上往下
	{
		if (i < end && arr[i] < arr[i + 1])//如果有右孩子,且左孩子的值小于右孩子
		{
			i++;
		}//i一定是左右孩子的最大值
		if (arr[i] > tmp)
		{
			arr[start] = arr[i];
			start = i;
		}
		else
		{
			break;
		}
	}
	arr[start] = tmp;
}
 
void HeapSort(int* arr, int len)
{
	//第一次建立大根堆(从后往前,多次调整)//根分别为4 3 2 1的子树
	for (int i = (len-1-1)/2; i >= 0; i--)//i的初值与结点总数有关,i=总结点数len-根-
	{
		HeapAdjust(arr, i, len - 1);
	}
	//每次将根和待排序的最后一个交换,然后再次调整(注意是待排序部分)
	int tmp;//用于交换
	for (int i = 0; i < len - 1; i++)
	{
		tmp = arr[0];
		arr[0] = arr[len - 1 - i];
		arr[len - 1 - i] = tmp;
 
		//再次调整
		HeapAdjust(arr, 0, len - 1 - i - 1);
	}
	
	return;
}

3.复杂度分析

建立大根堆的时间复杂度:O(n)

每次调整大根堆时间复杂度:O(logn),调整次数n-1次,总时间复杂度O(nlogn)

综合建堆和排序两个阶段,堆排序的时间复杂度为O(n+nlogn),通常简化为O(nlogn)。这是堆排序的平均时间复杂度;

空间复杂度O(1);

不稳定

相关推荐
.5486 分钟前
## Sorting(排序算法)
python·算法·排序算法
此剑之势丶愈斩愈烈12 分钟前
openssl 自建证书
java
面汤放盐14 分钟前
何时使用以及何时不应使用微服务:没有银弹
java·运维·云计算
0xDevNull24 分钟前
Spring Boot 自动装配:从原理到实践
java·spring boot·后端
qq_589568101 小时前
java学习笔记,包括idea快捷键
java·ide·intellij-idea
小怪吴吴2 小时前
idea 开发Android
android·java·intellij-idea
嘻嘻哈哈樱桃2 小时前
牛客经典101题题解集--动态规划
java·数据结构·python·算法·职场和发展·动态规划
一次旅行2 小时前
IDEA安装CC GUI新手指南
java·ide·intellij-idea
超梦dasgg2 小时前
Spring AI 智能航空助手项目实战
java·人工智能·后端·spring·ai编程
电科一班林耿超2 小时前
第 16 课:动态规划专题(二)—— 子序列与子数组问题:面试最高频的 DP 题型
数据结构·算法·动态规划