自我介绍: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。
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是用来消除堆的。
这篇文章就到此为止,如果觉得读完后对你有所帮助的话就点个赞吧,你们的支持是我最大的动力!