首页 > 其他分享 >堆排序的前提,建堆

堆排序的前提,建堆

时间:2024-07-17 09:59:07浏览次数:10  
标签:结点 子树 parent int 建堆 堆排序 左右 前提 child

堆排序就是借助堆的性质来实现排序,通过建堆,然后调整可以实现对需排序数组排序。下面来具体解释:

1:堆是完全二叉树,分为大根堆和小根堆,大根堆即是每个父结点大于等于左右子结点,小根堆即是每个父结点小于等子结点,下面两种图分别是一个大根堆和一个小根堆:

这里的70相对于56和30就是父结点,而56和30就是70的左右子结点。

2:还需要知道的是,完全二叉树中,若知父结点位置为i,则左右子结点为2i+1和2i+2,若已知子结点为i,则父结点为(i-1)/2,

例如此处0,1,2,3,4,5,6代表其在数组中的下标,对于5和6来说,2是其父结点,(5-1)/2和(6-1)/2都是2,有的地方写的是i/2-1,如果这样的话5/2-1就是1了,所以应该是(i-1)/2。

3:向下调整算法,这个算法的前提是要调整的根结点的左右子树必须是堆,所以要先建堆。例如:

以27为根结点,左右两个红框分别是其左右子树,并且观察可知,左右子树都是小根堆,那么就可以利用向下调整算法来实现对根结点的调整,使得变成小根堆。具体流程如下:

1)找到左右子结点小的那一个结点;

2)比较该子结点与父结点,如果子结点小,则与父结点交换;

3)交换完再更新父结点的位置,继续向下调整。

最后一个与父结点比较之后,可以看出父结点比子结点小,则不需要进行交换。根据上面步骤完成后,可以得到最后变成了小根堆。需要注意的是,上面过程只是一个例子,如果要把输入的数组建堆,由于向下调整算法根结点的左右子树必须是堆,就必须要从最后一个父结点开始,都要进行向下调整,使得其本身是堆,然后再做为父结点的子树,这样父结点的左右子树是堆,才能进行向下调整。

口语化表述就是:

以这颗树为例,想要调整为小根堆,对27这个结点调整就得保证以15和19为根的树是小根堆堆,同理,想要把15和19为根的树变成小根堆,就得保证15的左右子树(即以18和28为根的树)和19的左右子树(即以34和65为根的树)为小根堆,同理想要18、28、34和65的左右子树为小根堆,就得对其左右子树进行调整,直到叶子结点(左右子结点为空)为止,因为叶子结点就一个树,可以认为其是堆。

通过上述过程,即可建出一个小堆,建大堆方法类似,下面是建堆的参考代码:

void AdjustDown(int* a, int k, int parent)
{
	int child = 2 * parent + 1;

	while (child < k)
	{
		//找左右孩子小的那一个
		if (child + 1 < k && a[child + 1] < a[child])
			child++;
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}
int main()
{
    int arr[10] = {3,1,5,23,64,7,45,37,9,23};
    int k = sizeof(arr)/sizeof(arr[0]);
    int i = 0;
    for (i = (k - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr,k,i);
	}
}

上述代码注意的是:找左右子结点小的那个,我是先让左为小,然后去和右比较,右如果小的话,则对child++。循环停止条件为child>k,当父结点更新到叶子结点时,左右子结点就会大于边界,即数组个数k。所以小于k时继续调整。

这是进行堆排序的前提,后面还会实现堆排序,以及TopK问题的解决。

标签:结点,子树,parent,int,建堆,堆排序,左右,前提,child
From: https://blog.csdn.net/guaiguaiyalj/article/details/140395170

相关文章

  • Grafana Loki查询加速:如何在不添加资源的前提下提升查询速度
    GrafanaLoki查询加速:如何在不添加资源的前提下提升查询速度来自GrafanaLokiqueryacceleration:Howwespedupquerieswithoutaddingresources,介绍了Loki如何通过n-grams+布隆过滤器来加速查询。在过去的5年中,我们在平衡特性开发和支持大规模用户之时,改善了日志聚合......
  • Java实现堆排序算法详解及优化
    引言堆排序(HeapSort)是一种基于堆数据结构的比较排序算法。它具有良好的时间复杂度特性,在许多实际应用中表现出色。本文将详细讲解如何使用Java实现堆排序算法,并结合图解和实例代码,帮助您全面理解这一高级排序算法。同时,我们还将探讨堆排序的优化方法,以进一步提高其性能。......
  • 数据结构——二叉树之c语言实现堆与堆排序
    目录前言:1.二叉树的概念及结构1.1特殊的二叉树 1.2二叉树的存储结构  1.顺序存储2.链式存储 2.二叉树的顺序结构及实现 2.1堆的概念   ​编辑2.2堆的创建3.堆的实现3.1堆的初始化和销毁 初始化:销毁: 插入:向上调整:删除: 向下调整: 堆顶元素......
  • 常见的排序算法——堆排序
    本文记述了堆排序的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想J.W.JWilliams提出了堆排序的算法,该算法利用了二叉堆有序的性质,将排序的过程分为先构建堆再排序的两个阶段。先构建堆。从当前待排序范围一半的位置开始向第一个位置扫描,用......
  • 比赛获奖的武林秘籍:03 好的创意选取-获得国奖的最必要前提
    比赛获奖的武林秘籍:03好的创意选取-获得国奖的最必要前提摘要本文主要介绍了大学生电子计算机类比赛和创新创业类比赛创意选取的重要性,并列举了好的创意选取和坏的创意选取的例子,同时说明了好的创意选取具有哪些特点,同时对常见的创意选取途径与来源进行了基本介绍。正文好的......
  • 比赛获奖的武林秘籍:03 好的创意选取-获得国奖的最必要前提
    比赛获奖的武林秘籍:03好的创意选取-获得国奖的最必要前提摘要本文主要介绍了大学生电子计算机类比赛和创新创业类比赛创意选取的重要性,并列举了好的创意选取和坏的创意选取的例子,同时说明了好的创意选取具有哪些特点,同时对常见的创意选取途径与来源进行了基本介绍。正文......
  • 排序算法(3) 堆排序
    ​堆排序1.算法原理堆排序的原理与部分没听说过该排序方法的同学猜想的不同,它并不是将堆顶元素逐一弹出后压入数组中来得到一个有序的数组。这种方法在初始建堆时需要使用一个数组空间,在得到有序的数组时需要使用另一个数组空间。而堆排序则是在初始数组的基础上直接进......
  • git恢复到之前提交的记录
    项目搞崩了,还提交上去了怎么办?那当然是恢复到之前的提交记录了,那怎么操作呢?首先,到代码托管平台找到你想恢复的提交记录(在此以github为例)获取commitid首先,通过如下图操作获取到commitid{%asset_imgimage-20240706062921362.png'"...""文章配图"'%}{%asset_imgimag......
  • 装了一次没成功的前提下,ubuntu18.04+ros(melodic)安装 cartographer源码安装及测试---
    因为项目需要所以要安装cartographer,最开始也没仔细研究一下,随便找了一个csdn教程就跟着安装了,装了一下午,总是在最后编译的时候出错,晚上的时候心态崩了,咸鱼上找了个远程安装的,他好像是用小鱼的那个脚本安装,装了一个小时也没安装好。不死心的我又去咸鱼上找人,然后开口要两千块,两......
  • 数据结构/排序/堆排序 --- 逻辑讲解、代码实现、图形展示
    一、总体逻辑:    1.写一个交换的函数swap备用    2.写一个维护堆的性质的函数heapify备用    3.数组-> 堆(不明白的别急,后面会详细解释)    4.维护整个堆(看不懂别急别急别急)    5.堆顶和堆底的最后一个元素互换(不明......