数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解

这篇具有很好参考价值的文章主要介绍了数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解,数据结构,算法,排序算法,笔记,c语言,leetcode,经验分享
所有人都关心我飞的高不高,只有我妈关心我翅膀硬不硬

一、堆的应用

1. 堆排序

1.1 建堆

1.2 利用堆删除思想来进行排序

2.TOP-K问题

二、完结撒❀

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–
学习一个知识,我们起码要直到它的用途,那样才算学会了

一、堆的应用

1.堆排序

大家肯定都学过冒泡排序,快速排序等等,在学完堆之后我们也可以用堆来实现数据排序。
(ps:冒泡排序的时间复杂度:O(N^2))

1.1 建堆

升序:建大堆
降序:建小堆

建堆方式可能与大家预想的不太一样,但确实如此,升序我们需要建大堆,降序我们建小堆,再利用堆删除的思想进行排序,时间复杂度会低很多。

1.2 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序
代码实现:

void Swap(HPDataType* px, HPDataType* py)
{
	HPDataType tmp = *px;
	*px = *py;
	*py = tmp;
}

//向下调整O(logN)
void AdJustDown(HPDataType* a, int n, int parent)
{
	//从左孩子开始,child为小孩子那个
	int child = parent * 2 + 1;

	while (child < n)
	{

		if (child + 1 < n && a[child] > a[child + 1])
		{
			++child;
		}

		if (a[child] < a[parent])//小堆<,大堆>
		{
			Swap(&a[parent], &a[child]);
			parent = child;
			child = child * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//升序  大堆 O(N*logN)
//降序  小堆 O(N*logN)
void HeapSort(HPDataType* a, int n)
{
	//根据数组直接建堆 O(N)
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdJustDown(a, n, i);
	}

	//交换根和尾的位置,再向下对前end(end每次少一个)的数进行调整 O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdJustDown(a, end, 0);
		--end;
	}
}

只需要将要排序的数组地址和数组元素的总个数作为实参传过来,并且会向下调整,就可以实现排序。
这样的堆排序时间复杂赋为O(N*logN)

我们拿一个数组以降序排小堆为大家举例讲解:

int arr[] = {5,2,3,6,1,4,7}

逻辑图解:

数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解,数据结构,算法,排序算法,笔记,c语言,leetcode,经验分享
因为每次向下调整,根一定是数组中最小值,将最小值与当前数组访问的尾坐标进行交换,直到end为0,数组中的元素便以排好顺序。

堆排序的特性总结:

1. 堆排序使用堆来选数,效率就高了很多。

2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(1)

4. 稳定性:不稳定

2.TOP-K问题

TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。

比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。

对于Top-K问题,能想到的最简单直接的方式就是排序,但是:如果数据量非常大,排序就不太可取了(可能数据都不能一下子全部加载到内存中)。最佳的方式就是用堆来解决,基本思路如下:

1. 用数据集合中前K个元素来建堆

             前k个最大的元素,则建小堆
             前k个最小的元素,则建大堆

2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

为了更好的给大家讲解,我们可以现根据文件操作手动造出一些数据来

代码如下:

//造数据
void CreateNDate()
{
	int n = 10000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	for (int i = 0; i < n; ++i)
	{
		int x = rand();
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

以读的方式在data.txt文件中造出10000个随机数
效果如下:
数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解,数据结构,算法,排序算法,笔记,c语言,leetcode,经验分享当然,如果感觉10000个数据不够多,可以手动添加更多数据。

接下来我们就在这10000个数据中进行TOp-K问题的讲解

如何在这10000个数据中选出前K个最大的数呢?

上面对TOP-K问题的讲解已经给出了思路

我们可以先看一下代码实现:

//按照大小选出前k个值
void Tokp()
{
	//选出前k个最大数据
	printf("请输入前几个最大的值:>");
	int k = 0;
	scanf("%d", &k);

	//将数据中前k个数据存入到创建的minheap数组中
	const char* file = "data.txt";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen error");
		return;
	}

	int* minheap = (int*)malloc(sizeof(int) * k);
	if (minheap == NULL)
	{
		perror("malloc fail");
		return;
	}

	for (int i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &minheap[i]);
	}

	//建堆(向下建堆)
	for (int i = (k - 1 - 1) / 2; i >= 0; --i)
	{
		AdJustDown(minheap, k, i);
	}

	//判断大小进行替换
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)
	{
		if (minheap[0] < x)
		{
			minheap[0] = x;
			AdJustDown(minheap, k, 0);
		}
	}

	for (int i = 0; i < k; i++)
	{
		printf("%d ", minheap[i]);
	}

	fclose(fout);

}

这里对文件操作函数比如:fscanf,fprintf等不太熟悉的同学建议去官网进行查询如何使用之后再进行Top-K问题的学习
官网网址:cplusplus

假设我们要前10个最大的数据,那么输入k为10.
实现逻辑步骤:

1.输入k为10
2.以读的方式打开data.txt文件
3.创建一个10个数据空间大小(单位为字节)的数组
4.将文件中前10个数存入到数组中
5.对数组进行向下建堆(这里我们要前10个最大的数据,所以要建小堆)
6.将根节点以此与剩余9990个数据进行对比,大于根节点就进行替换再对前十个数据进行向下调整
7.打印数组,关闭文件

因为创建的是小堆,那么根节点的值一定是堆中最小的,如果后续数据大于根节点的值,替换后再向下调整,最后对比完数据前十个建好的小堆数据就是这10000个数据中最大的10个。

调用函数打印结果:
数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解,数据结构,算法,排序算法,笔记,c语言,leetcode,经验分享
因为10000个数据比较大,并且我们也并不知道这10000个数据中都有哪些数组,心里没有底
那么会不会有同学怀疑打印出的数值是否正确呢?

下面我教大家怎么检验所敲的该函数是否正确
我们可以在造数据的函数中做一些手脚
代码如下:

//造数据
void CreateNDate()
{
	int n = 100000;
	srand(time(0));
	const char* file = "data.txt";
	FILE* fin = fopen(file, "w");
	if (fin == NULL)
	{
		perror("fopen error");
		return;
	}

	for (int i = 0; i < n; ++i)
	{
		int x = (rand()+i)%10000;//检验程序准确
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}

这次我们将造出来的随机数该成100000个(判断数据增多会不会出现BUG)
再将造出来的每一个随机数都加上i并且余上10000

因为随机数所返回的数值大小范围为30000左右,我们为了让造出来的数更加随机,就每次加上i
余上10000的目的是为了让造出来的数字都在0~9999之间

之后我们直接执行该函数

执行后打开data.txt文件夹,我们会看到100000个数值在0~9999之间的数组

我们在该文件夹中随机更改5个数字,将这5个数字都改成大于10000的值,越大越好,之后保存

再对该文件里的所有数值进行Tokp,假设输入k为10,那么最后出来结构只要包含我们所更改的5个数据,就说明该函数打印前k个最大数据是正确的。

二、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤
数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解,数据结构,算法,排序算法,笔记,c语言,leetcode,经验分享文章来源地址https://www.toymoban.com/news/detail-845978.html

到了这里,关于数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构--堆的实现-大根堆/小根堆/堆排序/堆排序稳定性证明/TOP-K

            前言          逆水行舟,不进则退!!!                目录        认识堆        堆的创建         1,向下调整的方法建立堆         2,以向下调整的方式建立小根堆         3,向上调整的方式建堆        堆的插入        堆的删除              

    2024年02月04日
    浏览(42)
  • 【数据结构】堆的应用+TOP-K问题+二叉树遍历

    欢迎来到我的: 世界 希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 ! 该篇文章写到主要是:堆排序、 TOP-K问题、二叉树链式结构的实现、二叉树的遍历等等;如果有朋友还不太了解堆以及二叉树可以翻看我的上一篇博客:堆和二叉树的概念; 最

    2024年02月07日
    浏览(43)
  • Java 数据结构篇-实现堆的核心方法与堆的应用(实现 TOP-K 问题:最小 k 个数)

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍      文章目录         1.0 堆的说明         2.0 堆的成员变量及其构造方法          3.0 实现堆的核心方法         3.1 实现堆的核心方法 - 获取堆顶元素 peek()         3.2 实现堆的核心方法 - 下潜 do

    2024年02月04日
    浏览(40)
  • 数据结构——堆的应用 堆排序详解

    hello hello~ ,这里是大耳朵土土垚~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 💥 个人主页:大耳朵土土垚的博客 💥 所属专栏:数据结构学习笔记 💥对于数据结构顺序表、链表、堆有疑问的都可以在上面数据结构的专栏进行学习哦~ 有问题可以写在评论区或者私信

    2024年03月11日
    浏览(41)
  • 数据结构:堆的应用(堆排序和topk问题)

    个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》 堆排序即是 先将数据建堆,再利用堆删除的思想来排序。 将待排序数组建堆 将堆顶数据与数组尾部数据交换 调整新的堆顶数据,使其保证堆的结构不变 重复2,3步直到堆中没有数据结束。 降序 建小堆 (父节点 小于

    2024年02月13日
    浏览(29)
  • 数据结构与算法:堆排序和TOP-K问题

    朋友们大家好,本节内容来到堆的应用:堆排序和topk问题 我们在c语言中已经见到过几种排序,冒泡排序,快速排序(qsort) 冒泡排序的时间复杂度为O(N 2 ),空间复杂度为O(1);qsort排序的时间复杂度为 O(nlogn),空间复杂度为O(logn),而今天所讲到的堆排序在时间与空间复杂度上相

    2024年03月08日
    浏览(46)
  • 数据结构之堆排序以及Top-k问题详细解析

    个人主页:点我进入主页 专栏分类:C语言初阶      C语言程序设计————KTV       C语言小游戏     C语言进阶 C语言刷题       数据结构初阶 欢迎大家点赞,评论,收藏。 一起努力 目录 1.前言 2.堆排序 2.1降序排序 2.2时间复杂度 3.Top-k问题 4.总结         在上一篇文

    2024年02月05日
    浏览(31)
  • 【数据结构】---堆排序+TOP-K问题(了解游戏排行底层原理)

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:数据结构 🔑本章内容:堆排序+TOP-K问题 送给各位💌:日落跌入昭昭星野 人间忽晚 山河以秋 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇文章正文内容,下面

    2024年02月06日
    浏览(33)
  • 【数据结构】二叉树-堆(top-k问题,堆排序,时间复杂度)

     🌈个人主页: 秦jh__https://blog.csdn.net/qinjh_?spm=1010.2135.3001.5343 🔥 系列专栏: 《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm=1001.2014.3001.5482 ​​ 目录 堆排序 第一种  ​编辑 第二种  TOP-K问题 建堆的时间复杂度 向下调整建堆的时间复杂度:  向上调整建堆的时间

    2024年01月21日
    浏览(47)
  • 【数据结构】堆:堆的构建,堆的向上调整算法,堆的向下调整算法、堆排序

    目录 一、堆的定义 1、堆的定义: 2、根节点与其左、右孩子间的联系   二、堆的创建 1、堆的向下调整算法  2、堆的向上调整算法  三、堆排序 1、堆的定义: 堆可以被看作是 一棵 完全二叉树 的 数组 对象 。即在 存储结构上是数组,在逻辑结构上是一棵完全二叉树 。在

    2024年01月22日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包