前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【数据结构与算法】堆的应用:堆排序和topk问题

【数据结构与算法】堆的应用:堆排序和topk问题

作者头像
aosei
发布2024-01-23 14:12:47
830
发布2024-01-23 14:12:47
举报
文章被收录于专栏:csdn-nagiYcsdn-nagiY

一.堆排序

我们知道冒泡算法的时间复杂度是O(N^2),在数据量很多的时候,N^2是个很可怕的数字,二分算法的时间复杂度是O(logn),但是二分算法有限制条件,实用性并不高,那怎样才能高效实用的排序呢? 堆排序就能很好解决上述问题,堆排序的时间复杂度是O(logn),也没啥限制条件,可以实现高效排序。

这里要注意,排升序要建大堆,排降序要建小堆; 1.假设排升序,所以建大堆; 2.堆建好后,定义一个 end 变量,令其 =n-1(数组最后一个元素的下标是n-1) ; 3.堆建好后,数组第一个元素就是最大的,将其与最后一个数据交换,然后这个数据就不需要动了,为了保持它是个大堆,让它的前 end-1 个元素向下调整,然后end--,当 end<=0 时就结束循环。

堆排序不需要手搓个堆,只需要用到向下调整这个函数,所以使用堆排序时,只需写个向下调整就行了。

代码语言:javascript
复制
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void AdjustDown(int* arr, int parent, int n)
{
	assert(arr);
	int child = 2 * parent + 1;
	while (child < n)
	{
		if ((child + 1) < n&& arr[child + 1] > arr[child])
		{
			child++;
		}

		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			break;
	}
}
void Heapsort(int* arr, int n)
{
	assert(arr);
	int i = 0;
	for (i = (n - 2) / 2; i >= 0; i--)   //建堆
	{
		AdjustDown(arr, i, n);
	}
	int end = n - 1;
	while (end)
	{
		Swap(&arr[0], &arr[end]);

		AdjustDown(arr, 0, end);

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

二.topk问题

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

基本思路如下: 1. 用数据集合中前K个元素来建堆,注意: 前k个最大的元素,则建小堆; 前k个最小的元素,则建大堆; 2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素; 3.将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

我们可以从文件中读取数据,这样的实用性更高些; 假设找的是最大的前k个数据,所以建小堆; 具体: 1.创建一个k个元素的数组,模拟建堆,从文件中读取k个数据存入数组中; 2.从文件中取数据与数组的第一个元素比较,也就是堆顶的数据,因为是小堆,如果该数据比堆顶数据大,则将值赋给堆顶,成为新的堆顶,不用担心会出什么问题,因为是小堆,所以那些大的数据会往下沉,如果不大于堆顶的数据,则继续从文件中取数据出来比较; 3.当读取文件结束时就结束循环。

如果对文件操作不太熟悉的话,可参考->文件的基础操作

如要想检验你写的代码是否能解决topk问题时,可以在数据创建完成后,手动修改文件中的k个数据,如果是找最大的k个数据,那么只需要修改k个数据,且每个都大于原来文件的最大值,这样在测试代码时,输出的就是你修改的k个数据。

代码语言:javascript
复制
void Createdata(const char file,int n)   //创建数据
{
	int i = 0;
	int x = 0;
	FILE* fin = fopen("file", "w");  //打开文件
	if (fin == NULL)
	{
		perror("fopen fail");
		exit(-1);
	}
	for (i = 0; i < n; i++)
	{
		x = rand() % 100 + 1;   //利用随机数生成函数,创建k个范围在1~100之间的数据
		fprintf(fin, "%d\n", x);  //将数据写入文件中
	}
	fclose(fin);  //关闭文件
	fin = NULL;
}

void topk(const char file, int k)
{
	FILE* fout = fopen("file", "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		exit(-1);
	}
	HPdatatype* arr = (HPdatatype*)malloc(sizeof(HPdatatype) * k);
	if (arr == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	int i = 0;
	for (i = 0; i < k; i++)
	{
		fscanf(fout, "%d", &arr[i]);  //从文件中写入k个数据到数组中,模拟堆的创建
	}

	int val = 0, ret = 0;
	ret = fscanf(fout, "%d", &val);   //从文件中取数据
	while (ret != EOF)
	{
		if (val > arr[0])  //将取出的数据与堆顶数据比较,若大于,则其成为新的堆顶
		{
			arr[0] = val;
			AdjustDown(arr, 0, k);   //向下调整,保持小堆或是大堆
		}

		ret = fscanf(fout, "%d", &val);  //从文件中取数据
	}
	free(arr);
	fclose(fout);
	arr = NULL;
	fout = NULL;

}

int main()
{
	srand((unsigned int)time(NULL));
	const char file = "data.txt";
	int n = 1000;
	int k = 10;
	//Createdata(file,n);
	topk(file, k);
	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-01-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.堆排序
  • 二.topk问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档