数据结构:堆的应用(堆排序和topk问题)

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

数据结构:堆的应用(堆排序和topk问题),数据结构,数据结构,算法,c语言,开发语言,排序算法

个人主页 : 个人主页
个人专栏 : 《数据结构》 《C语言》


堆排序

堆排序即是 先将数据建堆,再利用堆删除的思想来排序。

  1. 将待排序数组建堆
  2. 将堆顶数据与数组尾部数据交换
  3. 调整新的堆顶数据,使其保证堆的结构不变

重复2,3步直到堆中没有数据结束。

建堆

  • 降序 建小堆 (父节点 小于等于 子节点)
  • 升序 建大堆 (父节点 大于等于 子节点)

建堆有两种思路,向上建堆 和 向下建堆。其中向下建堆优于向上建堆。

向下建堆:从最后一个子节点的父节点开始向前遍历待排序数组,不断向下调整。
如下: 对数组 {16, 72, 31, 94, 53, 23}建小堆
数据结构:堆的应用(堆排序和topk问题),数据结构,数据结构,算法,c语言,开发语言,排序算法
为什么不能从数组首元素开始呢? 因为向下调整的前提是 根节点的左子树 与 右子树都是大堆或小堆才可以使用。而空树 和 只有一个节点的树即可以是大堆或小堆。

堆的删除思想排序

  • 将堆顶数据 与 未排序数组尾部数据 交换
  • 向下调整新的堆顶数据,保证堆的结构不变
  • 将新未排序数组尾部数据 与 新堆顶数据交换

重复上述步骤,即可完成排序。
也可以解释为什么升序建大堆, 降序建小堆。小堆的堆顶数据永远是堆中数据最小的,将堆顶数据与未排序数组尾部交换,重复上述步骤。最小的数据就是数组最后一个元素,第二小的数据就是数字倒数第二个元素… 如此完成了降序。

如下

数据结构:堆的应用(堆排序和topk问题),数据结构,数据结构,算法,c语言,开发语言,排序算法

代码实现

//向下调整 小堆,假设该节点是 i, 右孩子节点是 2 * i + 1,左孩子节点是 2 * i + 2
void AdjustDown(HPDataType* data, int parent, int size)
{
	int child = parent * 2 + 1;

	while (parent < size)
	{
		//防止越界                    找左右孩子中最小的
		if (child + 1 < size && data[child] > data[child + 1])
		{
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
			swap(&data[parent], &data[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}


// 对数组进行堆排序
//先构建堆    升序:大堆     降序:小堆
//如降序,先建小堆,再将堆顶数据放入数组尾部,从新选择堆顶数据
void HeapSort(int* a, int n)
{
	建堆
	向上建堆   类似于插入数据
	//for (int i = 0; i < n; i++)
	//{
	//	AdjustUp(a, i);
	//}

	//向下建堆   向下调整的前提:该节点的左右子树要都是大堆或小堆
	//倒着从第一个非叶子结点开始向下建堆
	//             n 是数据个数 n-1 是数组最后一个元素   (子节点 - 1) / 2 == 父节点
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, i, n);
	}


	//将堆顶数据交换数组尾部数据,再选新的堆顶,再交换新的数组尾
	int end = n - 1;
	while (end > 0)
	{
		swap(&a[0], &a[end]);
		AdjustDown(a, 0, end);
		end--;
	}
}

int main()
{
	int arr[] = { 16, 72, 31, 23, 94, 53 };
	int size = sizeof(arr) / sizeof(arr[0]);

	HeapSort(arr, size);
	for (int i = 0; i < size; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

top k 问题

top k问题就是从N个数中选出前K个数 (N远大于K)
如下:我们随机创建 10000个小于1000000的数,从中找到5个最大的数

思路

我们可以先以前5个数建小堆,再遍历9995个数,如果该数大于堆顶的数,将该数与堆顶的数替换,再向下调整保证小堆结构,继续遍历剩下的数,直到遍历完9995个数。那么堆中的5个数就是10000中最大的5个数。

代码实现

如何检查代码的正确性?
我们可以先跑一遍造数据的代码,再在其创建的文件中随机改写5个数,使其大于1000000。然后我们就可以屏蔽造数据的函数,来运行PrintTopK函数。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void CreateNDate()
{
	// 造数据
	int n = 10000;
	srand((unsigned)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() % 1000000;
		fprintf(fin, "%d\n", x);
	}

	fclose(fin);
}




//从N个数中选处最大的K个数
//用前K个数建小堆(向下调整 or 向上调整),遍历N - K 个数,  (如果是大堆,那么有可能堆顶数据在一开始就是 N 个数中最大的)
//如果该数大于堆顶数据,堆顶数据 与 该数 交换在向下调整。
//遍历完 N - K 个数,那么堆中数据就是 N 个数中最大的 K 个数

void swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//小堆  父节点小于等于子节点
void AdjustDown(int* data, int parent, int size)
{
	int child = parent * 2 + 1;

	while (parent < size)
	{

		if (child + 1 < size && data[child] > data[child + 1])
		{
			child++;
		}

		if (child < size && data[parent] > data[child])
		{
			swap(&data[child], &data[parent]);

			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void PrintTopK(int k)
{
	const char* file = "data.txt";
	FILE* fin = fopen(file, "r");

	//读取前K个数据
	int* ans = (int*)malloc(sizeof(int) * (k + 1));
	if (ans == NULL)
	{
		perror("malloc:");
		exit(-1);
	}

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

	//建堆
	for (int i = (k - 1) / 2; i >= 0; i--)
	{
		AdjustDown(ans, i, k);
	}

	while (!feof(fin))
	{	
		//读取数据
		int val = 0;
		fscanf(fin, "%d", &val);

		if (val > ans[0])
		{
			swap(&val, &ans[0]);
			AdjustDown(ans, 0, k);
		}
	}

	
	//打印数据
	for (int i = 0; i < k; i++)
	{
		printf("%d ", ans[i]);
	}
	printf("\n");
}


int main()
{
	CreateNDate();

	int k = 0;
	scanf("%d", &k);
	PrintTopK(k);
	return 0;
}

总结

以上就是我对于堆的应用的理解!!!
数据结构:堆的应用(堆排序和topk问题),数据结构,数据结构,算法,c语言,开发语言,排序算法文章来源地址https://www.toymoban.com/news/detail-649166.html

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

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

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

相关文章

  • 数据结构:手撕图解堆的实现和TopK的应用

    要讲到堆,先要说两个关于二叉树的概念 满二叉树:一个二叉树如果每一层的节点数都是最大值,那么这个二叉树就是满二叉树 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是满二叉树的变形,对于深度为k的树有n个节点的二叉树,当且仅当其每一个节点都与

    2024年02月15日
    浏览(48)
  • 数据结构---手撕图解堆的实现和TopK的应用

    要讲到堆,先要说两个关于二叉树的概念 满二叉树:一个二叉树如果每一层的节点数都是最大值,那么这个二叉树就是满二叉树 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是满二叉树的变形,对于深度为k的树有n个节点的二叉树,当且仅当其每一个节点都与

    2024年02月16日
    浏览(38)
  • 数据结构学习分享之堆的详解以及TopK问题

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:数据结构学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你了解更多数据结构的知识   🔝🔝 本章就给大家带来久违的堆的知识,如果你还不知道数的相关知识,或者什么是完全二叉树,请跳转 树的介绍, 本章的堆结

    2024年02月05日
    浏览(98)
  • 【数据结构之二叉树简介·顺序存储·应用:堆·堆排序·TOPK问题】

    ​ 🕺作者: 迷茫的启明星 😘欢迎关注:👍点赞🙌收藏✍️留言 🎃相关文章 【数据结构从0到1之树的初识】 【数据结构】带你学会二叉树的链式存储的前中后序遍历,遍历推导及利用队列实现二叉树的层次遍历。 🏇家人们,码字不易,你的👍点赞🙌收藏❤️关注对我

    2024年02月01日
    浏览(35)
  • 数据结构-堆的实现及应用(堆排序和TOP-K问题)

    1.堆的知识点: 下面我们通过一张图片来更加深刻地理解堆 上面我们说过,堆的物理结构是一个数组,逻辑结构是一个完全二叉树,所以堆的实际结构类似于顺序表,只不过我们的处理方式类似于二叉树 那么我们就可以用顺序表那样的结构来表示堆了 于是我们可以写出这样的代码

    2024年02月07日
    浏览(52)
  • 经典TopK问题、优先级队列 与 堆的纠葛一文为你解惑——数据结构

    前言: 本篇文章以 TopK 问题为引,具体阐述了 PriorityQueue 实现的基本逻辑——堆 数据结构,以及PriorityQueue 的常用方法。如有问题欢迎看官朋友指正,如果觉得文章还不错的话,求点赞、收藏、评论 三连。 重点: 堆的基本实现逻辑 PriorityQueue 运用和源码分析 TopK 问题的解法

    2023年04月22日
    浏览(45)
  • 数据结构进阶篇 之 【堆的应用】(堆排序,TOP-K问题)详细讲解

    所有人都关心我飞的高不高,只有我妈关心我翅膀硬不硬 1.1 建堆 1.2 利用堆删除思想来进行排序 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀– 学习一个知识,我们起码要直

    2024年04月10日
    浏览(46)
  • 堆的实际应用(topk问题以及堆排序)

    目录 前言: 一:解决topk问题 二:堆排序 【1】第一种方法(很少用) 【2】第二种方法(很实用) 上一次我们进行了二叉树的初步介绍并实现了堆的基本功能,但堆的作用并不是存储数据, 它可以用来解决topk问题 ( 求一组数据较大或者较小的前k个 )以及 对数据进行排序 。 附上一

    2024年02月01日
    浏览(39)
  • 【数据结构】堆排序和TOPK问题

     😽 PREFACE 🎁欢迎各位→点赞👍 + 收藏⭐ + 评论📝 📢系列专栏:数据结构 🔊本专栏主要更新的是数据结构部分知识点 💪 种一棵树最好是十年前其次是现在 目录 0.利用堆的实现进行排序 1.堆排序 1.1 建堆 ​编辑  1.1.1 向上建堆 1.1.2 向下建堆 1.2 时间复杂度分析 1.3 堆排序

    2024年02月01日
    浏览(34)
  • 数据结构——堆排序的topk问题

    呀哈喽,我是结衣 今天给大家带来的堆排序的topk问题。topk就是在许多数中,找出前k个大的数,可能是几十个数,也可能是几千万个数中找。今天我们将要在1000000(一百万)个数中找出前10大的数。 C语言文件的读写 建堆 向下调整排序 随机数的产生 ps 向下调整和向上调整的

    2024年02月04日
    浏览(36)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包