上篇讲述了topK问题N个数中最大的前K个数,本篇则讲述统计一篇很长的英文文章中频次出现最高的10个单词。

 

例题2统计一篇很长的英文文章中频次出现最高的10个单词。

思路:  分治法 + hash + 小根堆

(1) 定义一个关联容器hash_map<string,int>,用于统计英文文章中每个单词出现的次数;定义一个vector<hash_map<string,int>::iterator>,用于存储小根堆K;

(2) 将英文文章中的前K个单词先填满topK堆;

(3) 调整topK堆为小根堆结构;

(4) 通过遍历将后面的单次出现的次数与堆顶单词出现的次数(此时堆顶单词出现的次数最小)比较,大于堆顶元素就入堆,并下调堆结构。

(5) 遍历结束,则小根堆中的单词即英文文章中频次出现最高的10个单词。

代码如下:

//  topK问题  统计一篇英文文章中出现频次最高的10个单词  分治法 + hash + 小根堆
#include<iostream>
#include<fstream>
#include<vector>
#include<string>
#include<hash_map>
#include<algorithm>

using namespace std;

//  调整堆
void adjustDown(vector<hash_map<string, int>::iterator> &topK, int i, int k)
{
	int min = i;
	int child = 2 * min + 1;
	while (min < k / 2)
	{
		if (child + 1 < k && topK[child]->second > topK[child + 1]->second)
			child++;
		if (child<k && topK[min]->second>topK[child]->second)
		{
			swap(topK[min], topK[child]);
			min = child;
			child = 2 * min + 1;
		}
		else
			break;
	}
}

//  建小根堆
void buildHeap(vector<hash_map<string, int>::iterator> &topK, int k)
{
	for (int i = k / 2 - 1; i >= 0; i--)
		adjustDown(topK, i, k);
}

//  获取文章中出现频次最高的前k个单词
void getTopK(hash_map<string, int> &essay, vector<hash_map<string, int>::iterator> &topK, int k)
{
	auto it = essay.begin();
	for (int i = 0; i < k; i++)
	{
		topK[i] = it;
		it++;
	}
	buildHeap(topK, k);
	for (; it != essay.end(); it++)
	{
		if (it->second>topK[0]->second)
		{
			topK[0] = it;
			adjustDown(topK, 0, k);
		}
	}
	//  输出出现频次最高的前k个单词及其频次
	for (int i = 0; i < k; i++)
		cout << topK[i]->first << " " << topK[i]->second << endl;
}
int main()
{
	//  读入英文文章
	ifstream in("data.txt");
	string word;
	hash_map<string, int> essay;  //  hash_map统计每个单词出现频次
	while (in >> word)
	{
		essay[word]++;
	}
	int k;
	while (cin >> k)
	{
		vector<hash_map<string, int>::iterator> topK(k, essay.begin());
		getTopK(essay, topK, k);
	}
	return 0;
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐