topK问题——统计一篇很长的英文文章中频次出现最高的10个单词

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

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

思路:

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

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

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

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

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

代码如下:

#include<iostream>
#include<fstream>
#include<string>
#include<vector>
#include<map>
#include<cassert>

using namespace std;

const int K = 10;
void adjustDown(vector<map<string,int>::iterator> &top,int i )
{
	int min = i;
	int child = 2 * min + 1;
	while (i < K / 2)
	{
		if ((child + 1 < K) && (top[child]->second > top[child + 1]->second))
			child++;
		if ((child<K) && (top[min]->second>top[child]->second))
		{
			swap(top[min], top[child]);
			min = child;
			child = 2 * min + 1;
		}
		else
			break;
	}
}

void topK(map<string, int> &essay, vector<map<string, int>::iterator> &top)
{
	auto it = essay.begin();
	//  初始化完全二叉树
	for (int i = 0; i < K; i++)
	{
		top[i] = it;
		it++;
	}
	//  建立小根堆
	for (int i = K / 2 - 1; i >= 0; i--)
	{
		adjustDown(top, i);
	}
	//  取topK
 	while (it != essay.end())
	{
		if (it->second > top[0]->second)
		{
			top[0] = it;                     //  大于堆顶元素,则入堆;
			adjustDown(top, 0);              //  重新调整为小根堆;

		}
		it++;
	}
	for (int i = 0; i < K; i++)
	{
		cout << top[i]->first << " ";
	}
	cout << endl;
}

int main()
{
	ifstream in("data.txt");          //  打开文件
	if (!in)
	{
		cerr << "无法打开输入文件" << endl;
		return -1;
	}
	string word;
	map<string, int> essay;
	while (in >> word)         //   istream &in 遇到空白字符(空格符、制表符和换行符)即停止读入。
	{
		essay[word]++;     //  添加到vector中 成员函数push_back()是用来添加未知数量的vector。 
	}
	vector < map<string, int> ::iterator> top(K, essay.begin());
	topK(essay, top);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/lizhentao0707/article/details/80925715
今日推荐