堆的难点易错点

目录

1.堆的性质

2.数组构建堆的方法

2.1堆向下调整算法

2.2堆是插入

3.构建堆的时间复杂度问题

4.堆的排序

1.堆的性质

2.数组构建堆的方法

 2.2 方法二:堆的插入

3.构建堆的时间复杂度的问题

 3.1方法一:向下调整的时间复杂度:

3.2 方法二:堆插入向上调整的时间复杂度

4.堆排序

4.1用堆实现升序

4.2  TopK的问题


1.堆的性质

1.堆总是一颗完全二叉树

2.堆顶父亲节点总是大于(大堆)或者小于(小堆)孩子节点

2.数组构建堆的方法

2.1 方法一:堆向下调整算法

接下来易构建小堆为例

根据学过的知识可以知道;最后一个非叶子节点=(最后的叶子节点-1)/2;

调整完最后一个非叶子节点后就可以往前调整,知道调整到根节点

具体的调整方法如下图

具体代码的实现

//一共有n个节点,数组为arr
//先找到最后一个非叶子节点
int parent=(n-1-1)/2;
//从最后一个非叶子节点一直开始调整到根节点
for(int i=parent;i>=0;i--)
{
  AdjustDown(arr,n,i);
}

AdjustDown的代码如下

void AdjustDown(int* arr, int n, int parent)
{
	int child = parent * 2 + 1;
	while (child<n)
	{
		if (child + 1 < n)
		{
			if (arr[child] >arr[child + 1])
				child++;
		}
		if (arr[child] <arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

最后的结果明显是符合小堆的;

 2.2 方法二:堆的插入

还是一构建小堆为列

 具体代码的实现

void AdjustUp(int* arr, int n, int child)
{
	int parent = (child - 1) / 2;//
	while (child > 0)//为什么不能用parent
	{

		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

注意:上面代码while循环的结束条件不能为parent>=0;如果插入的数据足够小,需要一直向上调整到根节点,这个时候parent==0;当执行玩child=parent时,chiid==0,此时在执行parent=(child-1)/2时,就会得到parent==0;此时该程序就不会跳出循环。最终出现bug;

3.构建堆的时间复杂度的问题

 3.1方法一:向下调整的时间复杂度:

3.2 方法二:堆插入向上调整的时间复杂度

4.堆排序

4.1用堆实现升序

思考:实现升序是构建小堆还是大堆?

如果构建的是小堆,第一次可以得到数组中的最小值,但是如何得到次小值呢? 继续构建一个堆的话会的到次小值,此时拍完之后,一共构建了n次堆如果用方法一构建堆,那么时间复杂度为O(n)为n^2,这时候还不如直接进行冒泡排序更贱直接。所以,在排升序的时候要建大堆,因为选出最大值后,将最大值后最后一个节点的值进行交换,再把堆的大小减减,这样在这个堆的范围内最大的值就会被排到末尾,循环往复就会得到一个降序的数组。

具体代码实现如下

//建堆过程
int parent = (n - 1 - 1) / 2;
	for (int i = (n - 2) / 2; i >= 0; i--)
	{
		AdjustDown(arr, n, i);
	}

	int end = n - 1;
	for (end = n - 1; end > 0; end--)
	{   //交换根节点和最后一个叶子节点
		Swap(&arr[end], &arr[0]);
		AdjustDown(arr,end, 0);
	}

得到的结果

4.2  TopK的问题

TopK的问题就是堆排序的应用。

案例:如果要从10亿个数据中找到5个最大值。

    这种情况下,对数据进行排序是非常不合理的,因为会占用极大的内存,这个时候就体现了堆排序的优点,先建立5个数据的小堆,在对数据进行比较,如果某一个数据大于小堆里面的最大值,就将小堆的根节点和该数据进行交换,在对新的堆进行向下调整,如此往复,就能得到最大的5个值。

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

年轻人江老Der

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

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

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

打赏作者

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

抵扣说明:

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

余额充值