堆排序详细讲解(C++,默认生成小根堆)


自我介绍:hello!这里是欧_aita的频道,一个初学数据结构与算法的小白。
小欧的今日语录: 每一个裂缝都是为透出光而努力
小欧的祝福语:在代码的海洋中,愿你的航程充满优雅和高效的算法风帆!
大家可以在评论区畅所欲言,可以指出我的错误,在交流中共同进步。
如果你也恰好在学习C++或者数据结构与算法那就来看看主页吧—— 欧_aita。

一.堆排序初理解⭐

1.1 堆排序的定义

堆排序是一种基于二叉堆数据结构的排序算法。它利用了堆的性质来实现对数组的原地排序。堆是一个特殊的树状数据结构,通常分为最大堆和最小堆。在最大堆中,每个节点的值都大于或等于其子节点的值,而在最小堆中,每个节点的值都小于或等于其子节点的值。

1.2 堆排序基本思想

1.2.1 建堆

建堆(Heapify): 将待排序的数组构建成一个二叉堆。这可以通过自底向上地对每个非叶子节点进行堆调整(Heapify)来实现。成功建堆

1.2.2 堆排序

堆排序: 将堆顶元素(最大元素或最小元素,取决于是最大堆还是最小堆)与数组末尾元素交换,然后重新调整堆,使得剩余元素重新构成一个堆。重复这个过程,直到整个数组有序。

1.3 复杂度

堆排序的关键在于堆的调整过程,确保每一步都维护堆的性质。堆排序的时间复杂度为 O(n log n),其中 n 是待排序数组的长度。由于堆排序是原地排序算法,空间复杂度为 O(1)。

二.堆排序代码详解⭐

2.1 up()

举个例子,如果我们有一个尚未进行排序处理的二叉树,而我们想要得到的是最小堆,就要对树中每个元素进行判断操作,如果该节点中的子节点有比该节点还小的数据元素,就进行 swap。下标为 6的数组元素2的up过程

void up(int u)
{
	while (u / 2 && h[u / 2] > h[u])
	{
		swap(h[u / 2], h[u]);
		u /= 2;
	}
}

注意左右两个子节点下标除以2都会是父节点下标。例如根节点的下标为1,他的左孩子节点下标就是2,右孩子节点下标就是3。在u/2是int型,2/2==3/2。所以使用一个判断条件就可以了。

2.2 down()

原理是和up差不多的,但是up是小值向上,但是down是大值向下。

void down(int u)
{
	int t = u;
	if (u * 2 <= S_size && h[u * 2] < h[t])t = u * 2;
	if (u * 2 + 1 <= S_size && h[u * 2 + 1] < h[t])t = u * 2 + 1;
	if (u != t)//不相同表示根节点不是最小值。
	{
		swap(h[u], h[t]);
		down(t);
	}
}

主函数

int main()
{
	scanf("%d%d", &n,&m);
	for (int i = 1; i <= n; i++)scanf("%d", &h[i]);
        S_size = n;

	for (int i = n / 2; i; i++)down(i);

	while (m--)
	{
		printf("%d", h[1]);
		h[1] = h[S_size];
		S_size--;
		down(1);
	}
	return 0;
}

n和m分别代表的是入堆元素个数以及操作次数。
不难发现m是用来消除堆的。

这篇文章就到此为止,如果觉得读完后对你有所帮助的话就点个赞吧,你们的支持是我最大的动力!

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Aitee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值