继续学习堆

1.对堆的排序

之前我们学习过了以顺序表为结构基础的对堆的改变,向上调整,向下调整。

  都是基于对数组下标的调整。今天我们来学习一下对 堆的排序。

对堆该如何排序,如果我们对堆实现我们的升序,该如何实现呢。

当然堆的底层结构就是我们的数组,我们当然可以是用冒泡排序,时间复杂度是O( n^2 );

我们可以尝试用堆的功能来实现。假如我们使用建设小堆的原理来排序,那么堆顶一定是最小的元素,剩下的按照左子树比右子树小的原则进行排列,但不一定是我们要的升序。

建立的是大堆,那我们的堆顶就是最大的元素,既然最大的我们有了,加上我们之前学过一次如何删掉堆顶元素,所以我们建设大堆,接着交换堆顶和堆尾,像删掉堆顶那样,再进行不加入刚才最大元素,重新排列,找出此时的堆的最大元素,然后再交换。。。好了我们可以尝试实现一下。

void HeapSort(innt* arr, int x)
{
	//排升序 用向下调整建大堆 然后交换首尾 再减小sz
	for (int i = (x - 2) / 2; i >= 0; i--)
	{
		  adjustdown(arr, x, i);
	}
	while (x)
	{
		Swap(&arr[0], &arr[x - 1]);
		x--;
		adjustdown(arr, x, 0);
	}

}//这个的时间复杂度和向上调整一样,都是O(N*logN)

值得一提的是升序建大堆,降序建小堆,因为我们需要排出最大的,次打的。。。

2.TopK问题

这个问题就是假设我们在一万个数里面找到前十个元素

我们可以想到的方法是快速排序,它的时间复杂是O(N*logN)

冒泡排序时间复杂度是O( n^2 ),n是一万还好,如果是n是一亿甚至更大呢,那时间将非常大,所以我们将用堆实现一种更快的。

方法:要最大的前多少个元素我们就建一个小堆注意了和我们刚才的不一样,这次我们要建立的是小堆,怎么会是小堆呢,我们明明需要的是最大的数,假设我们就挑出了这一万个数的前十个任意的数,放进我们的小堆里面,堆顶是不是最小的数字呢,如果我们开始遍历剩下的数字,如果有比堆顶大的元素我们就把堆顶元素将这个大数存进去,再重新对这个堆排序,那么堆顶又出现了此时堆里面最小的元素,那么我们依次遍历下去,我们的堆里面如果存进去最大的十个数之一,他是永远被换出堆的情况的,因为没有比他们十个数还大的数被换,只要进堆了,每次的排序都是将不是最大的十个数往出筛选,将大数往堆里面放。虽然建立的小堆,但我们把比堆顶大的数往进放。

我们此时需要一万个数,那我们实现在文件里面,这样更加直观清晰。我们先把一万个随机的数字,在文件夹中生成好,一会再调用。

void CreatHeap()
{
	int m = 10000;
	srand(time(0));
	char* file = "ss.text";
	FILE* fin = fopen(file, "w");
	//先创建数
	while (m)
	{
		int x = rand();
		fprintf(fin, "%d\n", x);
		m--;
	}
	fclose(fin);

}

建立好一万个数字,接着我们找出最大的前n位数

void TopK()
{
	printf("输入你要的top");
	int m = 0;
	scanf("%d", &m);
	char* file = "ss.text";
	FILE* fout = fopen(file, "r");
	if (fout == NULL)
	{
		perror("fopen fail");
		exit(1);
	}
	//建小堆
	innt* arr = (innt*)malloc(sizeof(innt) * m);
	if (arr == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	for (int i = 0; i < m; i++)
	{
		fscanf(fout, "%d", &arr[i]);
	}
	//向下调整
	for (int j = (m - 2) / 2; j < m; j++)
	{
		adjustdown(arr, m, j);
	}
	int x = 0;
	while (fscanf(fout, "%d", &x) != EOF)//将大数往堆里面放
	{
		if (x > arr[0])
		{
			arr[0] = x;
			adjustdown(arr, m, 0);
		}
		
	}
	for (int i = 0; i < m; i++)
	{
		printf("%d\n", arr[i]);
	}
	fclose(fout);
}

感谢观看,欢迎指出错误

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值