[C语言][剑指offer篇]--最小的k个数(堆排序)

1. 题目描述

 输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


2. 理清思路

2.1 堆排序的基础概念

2.1.2 完全二叉树

 如果二叉树的深度为n,则除第n层外其余所有层节点都有2个子节点,且叶子节点从左到右依次存在。如下图所示。
在这里插入图片描述

2.1.3 大根堆

 在完全二叉树的基础上,每个节点都要大于等于左右节点,假设K表示节点,则大根堆满足 Ki >= K2i && Ki >= K2i+1 ,1 <= i <= (n/2) ,n代表节点个数,如图所示:
在这里插入图片描述

2.1.4 小根堆

 在完全二叉树的基础上,每个节点都要小于等于左右节点,假设K表示节点,则大根堆满足 Ki <= K2i && Ki <= K2i+1 ,1 <= i <= (n/2) ,n代表节点个数, 如图所示:
在这里插入图片描述

堆排序的基本思想

 堆排序(Heap Sort)就是利用堆进行排序的算法,它的基本思想是:

  • 将待排序的序列构造成一个大顶堆(或小顶堆)。
  • 此时,整个序列的最大值就是堆顶的根结点。将它移走(就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值)。
  • 然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的此大值。
  • 如此反复执行,便能得到一个有序序列了。

3. 代码实现

void swap(int k[], int i, int j)
{
	int temp;

	temp = k[i];
	k[i] = k[j];
	k[j] = temp;
}

/*
@k:数组首地址
@s:双亲
@n:待构造的节点个数
*/
void HeapAdjust(int k[], int s, int n)
{
	int i, temp;

	temp = k[s];//固定住双亲节点

	for( i=2*s; i <= n; i*=2 )//2*s 表示左孩子 , 2*s + 1 表示右孩子
	{
		if( i < n && k[i] < k[i+1] )
		{
			i++;//指向右孩子
		}

		if( temp >= k[i] )//若双亲大于左孩子或右孩子,则退出循环,往根节点方向继续构造
		{
			break;
		}

		k[s] = k[i];//若双亲小于左孩子或右孩子,则双亲替换为左孩子或右孩子,此时的双亲
		s = i;//并且把双亲的下标也替换掉。
	}

	k[s] = temp;//把开始保存的双亲替换掉左孩子或右孩子。
}

/*从下往上,从左到右构造大根堆*/
void HeapSort(int k[], int n)
{
	int i;
	
	/*第一次构造大根堆*/
	for( i=n/2; i > 0; i-- )// n/2 表示拿到倒数第二层左节点的下标 
	{
		HeapAdjust(k, i, n);//构造大根堆
	}

	/*根节点和第(n-i)个节点交换,并将 (n-i)个节点重新构造大根堆*/
	for( i=n; i > 1; i-- )
	{
		swap(k, 1, i);//根节点和第(n-i)个节点交换
		HeapAdjust(k, 1, i-1);//将 (n-i)个节点重新构造大根堆
	}
}



int* getLeastNumbers(int* arr, int arrSize, int k, int* returnSize){

    int i = 0;
    int *ans;

    if(arr == NULL)
    {
        *returnSize = 0;
        return NULL;
    }

    ans = (int *)malloc(sizeof(int)*(arrSize+1));
    ans[0] = -1;
    for(i = 1; i <= arrSize; i++)
    {
        ans[i] = arr[i-1];
    }

    HeapSort(ans,arrSize);

    *returnSize = k;

    return &ans[1];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛应用于计算机科学和软件开发的编程语言。它具有强大的功能和灵活性,适用于开发各种类型的应用程序。 C语言专题精讲是一个对C语言进行深入学习和讲解的系列文章或课程。它汇总了C语言相关的重要知识点和技巧,旨在帮助学习者更好地理解和运用C语言。 这个专题中的笔记涵盖了C语言的各个方面,包括基本语法、数据类型、运算符、流程控制、函数、数组针、结构体、文件操作等。通过系统性的学习和总结,这些笔记可以帮助学习者逐步掌握C语言的核心概念和常用技巧。 在这个专题中,学习者可以学到如何编写简单的C程序,如何使用变量和运算符进行计算,如何使用条件和循环语句控制程序流程,如何使用函数进行代码的模块化,如何使用数组针进行数据的处理,如何使用结构体组织复杂数据,如何进行文件的读写等等。 C语言专题精讲的目的是帮助学习者全面、深入地了解C语言的各个方面,并能够独立编写和调试简单到中等难度的C程序。通过反复实践和练习,学习者可以逐渐提高自己的编程能力,并为进一步学习更高级的编程语言打下坚实的基础。 总之,C语言专题精讲的笔记汇总是一份重要的学习资料,可以帮助学习者系统地学习和掌握C语言的基础知识和常用技巧,为他们未来的编程之路打下坚实的基石。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值