IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 堆的难点易错点 -> 正文阅读

[数据结构与算法]堆的难点易错点

目录

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个值。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-11-16 19:05:28  更:2021-11-16 19:06:10 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 11:37:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码