6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客

本章重点

1.使用堆来完成堆排序

2.使用堆解决TopK问题

一.堆排序

1.1 思路

由于堆的特殊性质,可以使用堆来堆数组进行排序,而且效率较高。

这里以排降序为例。

1.根据数组建堆

2.排序

a.将堆顶数据和最后一个数据交换,n--

b.0~n -1位置还满足向下调整算法。再次调整为堆

c.继续交换

如下图

排升序:建立大根堆

排降序:建立小根堆

1.2 代码

cpp 复制代码
//降序为例
void HeapSort(int* arr, int n)
{
	//1.将数组建堆,使用向下调整算法建立小根堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		Adjustdown(arr, n, i);
	}

	//2.排序
	//a.将堆顶数据和最后一个数据交换,再让n--,
	//b.此时0~n-1还是可以使用调整算法调整为堆
	//c.继续交换
	int end = n - 1;
	while (end >= 0)
	{
		swap(arr[0], arr[end]);
		Adjustdown(arr, end, 0);
		end--;
	}
}

1.3 简单测试

测试主函数代码如下

cpp 复制代码
int main()
{
	DataType arr[] = { 1,5,9,7,5,3,4,6,8,2,4,4,15,19,59,75,73,53,46,82 };

	cout << "排序前:" << endl;
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		cout << arr[i] << " ";
	}

	cout << endl << "排序后:" << endl;
	HeapSort(arr, sizeof(arr) / sizeof(arr[0]));
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		cout << arr[i] << " ";
	}
	return 0;
}

测试结果

二.TopK问题

TopK问题是,如何从n个数据中找出前k个最大,或者最小的数据。

Leetcode原题:面试题 17.14. 最小K个数 - 力扣(LeetCode)

2.1 思路:

  1. 我们建立一个大小为 k 的堆

  2. 求最小,建立大根堆。求最大,建立小根堆。

  3. 遍历数组,遇到比堆顶数据小的数据 i 时,将数据 i 替换堆顶。然后对堆使用向下调整

2.2 C语言代码(手写堆)

cpp 复制代码
//向下调整算法,求最小,建立大根堆
void Adjustdown(int*arr,int n,int root)
{
    int parent=root;
    int child=parent*2+1;
    
    while(child<n)
    {
        if(child+1<n && arr[child]<arr[child+1] )
            child++;

        if(arr[child]>arr[parent])
        {
            int t=arr[child];
            arr[child]=arr[parent];
            arr[parent]=t;

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


int* smallestK(int* arr, int arrSize, int k, int* returnSize)
{
    *returnSize=k;
    if(*returnSize==NULL)
        return NULL;
    //定义k大小的数组,并拷贝前k个数据,并且调整为堆
    int *Rarr=(int*)malloc(sizeof(int)*k);
    for(int i=0;i<k;i++)
    {
        Rarr[i]=arr[i];
    }

    for(int i=(k-1-1)/2;i>=0;i--)
    {
        Adjustdown(Rarr,k,i);
    }

    //TopK法,遍历原数组,遇到比堆顶还要小,删堆顶,插入新元素
    //这里从k开始,是因为前面已经拷贝了k个数据
    for(int i=0;i<k;i++)
    {
        printf("%d ",Rarr[i]);
    }
    printf("\n");

    for(int i=k;i<arrSize;i++)
    {
        if(arr[i]<Rarr[0])
        {
            //1.替换数据
            Rarr[0]=arr[i];
            //2.重新调整
            Adjustdown(Rarr,k,0);
        }
    }
    return Rarr;
}

2.3 C++代码(使用优先级队列 priority_queue)

优先级队列 priority_queue 就是堆

cpp 复制代码
//优先级队列
//1.默认的为大根堆
priority_queue<int, vector<int>> pq;

//使用greator为小根堆
priority_queue<int, vector<int>, greater<int>>pq;

解题代码

cpp 复制代码
class Solution {
public:
    vector<int> smallestK(vector<int>& arr, int k) 
    {
        vector<int> retarr(k);
        if(k==0)
            return retarr;
        //使用优先级队列建立大根堆
        priority_queue<int,vector<int>> pq;
        
        //1.拷贝k个数据
        for(int i=0;i<k;i++)
        {
            pq.push(arr[i]);
        }

        //2.遍历数组,替换比堆顶大的数据
        for(int i=k;i<arr.size();i++)
        {
            if(arr[i]<pq.top())
            {
                pq.pop();
                pq.push(arr[i]);
            }
        }

       for(int i=0;i<k;i++)
        {
            retarr[i]=pq.top();
            pq.pop();
        }
        return retarr;
    }
};
相关推荐
Pandaconda8 分钟前
【Golang 面试题】每日 3 题(三十九)
开发语言·经验分享·笔记·后端·面试·golang·go
半盏茶香9 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦17 分钟前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
CodeJourney.29 分钟前
小型分布式发电项目优化设计方案
算法
DARLING Zero two♡1 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
带多刺的玫瑰1 小时前
Leecode刷题C语言之从栈中取出K个硬币的最大面积和
数据结构·算法·图论
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
薯条不要番茄酱1 小时前
【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题
算法·动态规划
小林熬夜学编程1 小时前
【Python】第三弹---编程基础进阶:掌握输入输出与运算符的全面指南
开发语言·python·算法