题目:
本公司现在要给公司员工发波福利,在员工工作时间会提供大量的水果供员工补充营养。由于水果种类比较多,但是却又不知道哪种水果比较受欢迎,然后公司就让每个员工报告了自己最爱吃的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);
}