堆的应用(堆排序、Top-K问题)

news/2024/5/20 5:58:45 标签: 开发语言, c语言, 数据结构,

文章目录

  • 1 排序
  • 2 Top-K问题

1 排序

排序是一种基于二叉(通常使用数组实现)的排序算法。
它的基本思想是利用这种数据结构的性质,通过建立一个(大或小),使得的根节点是所有节点中的最大值(大)或最小值(小)。然后,将根节点与的最后一个节点交换,使得最大值或最小值进入有序区。接着,对剩余的未排序部分重新调整成,重复这个过程,直到整个数组有序。

调整中都用到了向下调整,因此掌握了向下调整法,就可以完成排序。对该算法不清楚的,可以参考这篇文章,里面进行了详细的介绍:详解(C语言实现)
排序步骤:

  1. 构建初始(建: 从最后一个非叶子节点开始,对每个节点进行向下调整(调整成的性质,大或小)。
    排升序:建大,原因如下:
    排序中,升序排序要建立大的主要原因是为了保证每次选择顶元素都是中的最大值
    在排升序时,每次选择顶元素与的最后一个元素交换,由于顶是最大值,将其与末尾元素交换后,最大值就被移到了数组的末尾,而在交换后,需要重新调整,使剩余部分重新构成大,这样,下一次选择顶元素时,依然得到的是剩余元素中的最大值。通过这个过程,每次都能选择到当前中的最大值,将其移到数组末尾,逐步形成有序部分,从而实现升序排序。
    排降序:建小,原因如下:
    排序中,降序排序要建立小的主要原因是为了保证每次选择顶元素都是中的最小值
    在排降序时,每次选择顶元素与的最后一个元素交换,由于顶是最小值,将其与末尾元素交换后,最小值就被移到了数组的末尾,而在交换后,需要重新调整,使剩余部分重新构成小,这样,下一次选择顶元素时,依然得到的是剩余元素中的最小值。通过这个过程,每次都能选择到当前中的最小值,将其移到数组末尾,逐步形成有序部分,从而实现降序排序。
  2. 排序: 交换的根节点(最大值或最小值)与的最后一个节点,并对剩余部分重新调整成
    重复: 重复步骤2,直到整个数组有序。

例如利用排序对该数组{ 8, 5, 3, 9, 1}进行排降序,过程如下:

  1. 建小
    在这里插入图片描述
  2. 排序
    在这里插入图片描述

代码如下:

void AdjustDown(int* nums, int n, int parent)
{
	// 左孩子的索引
	int child = parent * 2 + 1;
	// 循环直到没有左孩子
	while (child < n)
	{
		// 如果右孩子存在且比左孩子小,选择右孩子
		//若实现大根,这里nums[child + 1] < nums[child]的 < 换成 >
		if (child + 1 < n && nums[child + 1] < nums[child])
		{
			++child;
		}
		// 如果孩子比父亲小,交换它们的值
		//若实现大根,这里nums[child] < nums[parent]的 < 换成 >
		if (nums[child] < nums[parent])
		{
			// 孩子比父亲大,的有序性已经恢复,退出循环
			int tmp = nums[child];
			nums[child] = nums[parent];
			nums[parent] = tmp;
		}
		else
		{
			break;
		}
		// 更新父亲和孩子的索引
		parent = child;
		child = parent * 2 + 1;
	}
}

void HeapSort(int* nums, int n)
{
	//建
	//升序,建大
	//降序,建小
	for (int i = (n - 2) / 2; i >= 0; --i)
	{
		AdjustDown(nums, n, i);//非叶子节点开始向下调整
	}

	int end = n - 1;
	while (end > 0)
	{
		//交换的根节点与的最后一个节点
		int tmp = nums[end];
		nums[end] = nums[0];
		nums[0] = tmp;
		//并对剩余部分重新调整成
		AdjustDown(nums, end, 0);
		end--;
	}
}

总之,排序是一种选择排序,它利用了的性质:顶的数据,是中最大的数据(或者最小的数据)。该算法通过不断选择顶元素,将其与的最后一个元素交换,然后调整,使剩余部分重新构成,重复这个过程直到整个数组有序。

2 Top-K问题

Top-K 问题是在一个包含大量数据的集合中,找出前 K 个最大或最小的元素数据的问题。通常数据量都是比较大的。

  1. 关于解决TOP-K问题,我们首先想到的是对这个数据集合拍升序或者降序,然后取前 K 个数据,就能解决这个问题。该方法的缺点是不适用于数据量极大的情况。这是因为,利用排序算法,需要将数据加载到内存中,在内存中进行排序,然而当数据量大到无法一次性加载到内存中时,排序算法的效率就会受到限制。
  2. 因此,就有人提出了使用来解决这个问题。该算法的思想是:用数据集的前k个数据,建一个大小为 K 的小顶(Top K 最大问题)或大顶(Top K 最小问题)。依次遍历剩余n - k个元素,将元素与顶比较,若大于(或者小于)顶,则替换顶,并进行调整。这样,最终中的元素就是前 K 个最大或最小的元素。

例如:面试题 17.14. 最小K个数
过程如下:

  1. 用数据集的前k个数据,建一个大小为 K 的小根
  2. 依次遍历剩余n - k个元素,将元素与顶比较,若大于顶,则替换顶,并进行调整。

代码如下:

 //向下调整算法
 void AdjustDown(int* nums, int n, int parent)
 {
     int child = parent * 2 + 1;
     while (child < n)
     {
         if (child + 1 < n && nums[child + 1] > nums[child])
         {
             ++child;
         }
         if (nums[child] > nums[parent])
         {
             int tmp = nums[child];
             nums[child] = nums[parent];
             nums[parent] = tmp;
         }
         else
         {
             break;
         }
         parent = child;
         child = parent * 2 + 1;
     }
 }
int* smallestK(int* arr, int arrSize, int k, int* returnSize)
{

    int* nums = (int*)malloc(sizeof(int) * k);
    for (int i = 0; i < k; ++i)
    {
        nums[i] = arr[i];
    }
     //前k个数建大
    for (int i = (k - 2) / 2; i >=0; --i)
    {
        AdjustDown(nums, k, i);
    }
    //依次遍历剩余n - k个元素
    for (int i = k; i < arrSize; ++i)
    {
        //将元素与顶比较,若大于顶,则替换
        if (k > 0 && arr[i] < nums[0])
        {
            nums[0] = arr[i];
            //进行调整
            AdjustDown(nums, k, 0);
        }
    }

    *returnSize = k;
    return nums;
}

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。
创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!
如果本篇博客有任何错误,请批评指教,不胜感激 !!!
在这里插入图片描述


http://www.niftyadmin.cn/n/5222814.html

相关文章

Modbus平台:协议中间件(支持Modbus TCP、RTU、ASCII)

该程序可放置外网中&#xff0c;适用于DTU长连接&#xff08;心跳包必须包含DTU&#xff0c;可以是tcp/udp&#xff09;&#xff0c;也可以在内网中&#xff0c;短连接访问设备server 支持协议&#xff1a;Modbus TCP | RTU | ASCII 连接方式&#xff1a;TcpAtive: TCP主动 | …

Vim多行编辑

Vim多行编辑 Ctrlq进入多行编辑模式&#xff0c;然后上下选择要编辑的行 按下I或者Shifti&#xff0c;进入编辑模式 编辑的时候多行不会同时变化&#xff0c;不要担心&#xff0c;确实是多行编辑 编辑完成&#xff0c;想要结束多行编辑&#xff0c;按下Esc&#xff0c;此时…

GAN:DCGAN-深度卷积生成对抗网络

论文&#xff1a;https://arxiv.org/pdf/1511.06434.pdf 发表&#xff1a;ICLR 2016 一、架构创新 1&#xff1a;全卷积网络&#xff1a;用逐步卷积代替确定性的空间池化函数&#xff08;如maxpooling&#xff09;&#xff0c;使网络学习自己的空间下采样。使用这种方法&#…

​无人机摄影测量

无人机摄影测量技术是传统航空摄影测量手段的有力补充&#xff0c;具有机动灵活、高效快速、精细准确、作业成本低、生产周期短、影像获取空间分辨率高、高危地区探测等优势。无人机与航空摄影测量相结合使得“无人机数字低空遥感”成为航空遥感领域的一个崭新发展方向。无人机…

微服务--04--SpringCloudGateway 网关

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.网关路由1.1 认识网关在SpringCloud当中&#xff0c;提供了两种网关实现方案&#xff1a; 1.2.快速入门1.3.路由过滤 2.网关登录校验2.1.鉴权思路分析2.2.网关过滤…

MFC居中显示文字及其应用

首先获取窗口客户区矩形,然后使用DrawText输出,设置DT_CENTER 和 DT_VCENTER标志; 输出如上图;没有实现垂直居中; 最终的代码如下; void CcenterView::OnDraw(CDC* pDC) {CcenterDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);if (!pDoc)return;// TODO: 在此处为…

【区块链】产品经理的NFT初探

常见的FT如比特币&#xff08;BTC&#xff09;&#xff0c;以太币&#xff08;ETH&#xff09;等&#xff0c;两个代币之间是完全可替换的。而NFT具有唯一性&#xff0c;不可以互相替换。本文作者对NET的发展现状、相关协议、应用场景等方面进行了分析&#xff0c;一起来看一下…

MPPT工作流程及算法和硬件的选择

MPPT算法选择 目前&#xff0c;MPPT算法有开路电压比率(离线)、短路电流比率(离线)、观察调节(在线)、极限追踪控制法(在线)。 在光伏控制系统中&#xff0c;因为日照、温度等条件的变化&#xff0c;光伏电池的输出功率也是在不断变化的&#xff0c;为保证使得光伏电池的输出功…