TopK问题

题目:

本公司现在要给公司员工发波福利,在员工工作时间会提供大量的水果供员工补充营养。由于水果种类比较多,但是却又不知道哪种水果比较受欢迎,然后公司就让每个员工报告了自己最爱吃的k种水果,并且告知已经将所有员工喜欢吃的水果存储于一个数组中。然后让我们统计出所有水果出现的次数,并且求出大家最喜欢吃的前k种水果。 
void GetFavoriteFruit(const vector& fruits,size_t k); 

通过对该问题进行分析,属于TopK问题,即通过对某一性质的排序得到一个区间的前K个值。


思路:
该题主要考察我们对STL中的容器和算法的应用
        1、我们可以通过map将vector中存在的所有水果和数量统计出来,
        2、但是我们还无法得到出现次数在前K个的水果,我们可以建大小为K的小堆,然后通过每次和堆顶元素(水果出现的次数)的比较来筛选出到当前为止最大的K个,直至将map遍历完,即可找到出现最多的前K种水果。
        3、由于我们要效率高,自己实现堆又比较麻烦,所以我们借助STL中的queue头文件里的优先级队列priority_queue来实现我们需要的操作。

priority_queue<Type, Container, Functional>
        优先级队列通过一系列堆算法来实现通过优先级将队列排序,优先级队列有三个模板参数,Type表示将哪种数据类型排序,Container表示优先级队列由哪种容器构成,Functional表示数据类型的比较函数
        三个参数,第一个数据类型不能省略;第二个参数可以省略,但必须是数组形式的容器,如vector、queue,STL默认用的vector;第三个参数为数据比较的方式,可以省略,若数据不是基本类型一般需要自己实现仿函数或operator<来实现,STL默认operator<,默认以大堆的形式排序,即第一个元素优先级最大。

代码实现:

#pragma once
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<queue>
using namespace std;

struct Compare   //自定义仿函数,实现对优先级队列中的vector进行比较(只比较水果出现的次数即第二个元素的大小)
{
	bool operator()(map<string, int>::iterator it1, map<string, int>::iterator it2)
	{
		return it1->second < it2->second;  
	}
};

void GetFavoriteFruit(vector<string>& fruits, size_t k)
{
	//1.通过map统计每种水果的数量
	map<string, int> fruits_map;
	int size = fruits.size();
	for (int i = 0; i < size; ++i)    //将每种水果放入map
	{
		fruits_map[fruits[i]]++;
	}
	
	map<string, int>::iterator it = fruits_map.begin();
	while (it != fruits_map.end())    //测试map是否正确的代码
	{
		cout << it->first << " " << it->second << endl;
		++it;
	}
	//2.通过建K大小的小堆来找出前k种水果
	//也可通过优先队列(堆算法)来实现对水果的个数进行排序

	priority_queue<map<string, int>::iterator, vector<map<string, int>::iterator>, Compare> q;
	for (it = fruits_map.begin(); it != fruits_map.end(); ++it)
	{
		q.push(it);    //将包含水果和次数信息的迭代器类型放入优先队列
	}
	//此时优先级队列已经有序存储,只需打印前K个即可
	while (k--)
	{
		cout << q.top()->first << " " << q.top()->second << endl;
		q.pop();
	}
}
void TestTopK()
{
	vector<string> fruits = { "a", "a", "b", "c", "a", "c" };
	size_t k;

	GetFavoriteFruit(fruits, 2);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值