[算法]大文本文件中找词频最高的10个词
问题描述:一个大的英文文本,找到其中出现次数最高的10个单词
思路:
大文本文件肯定是一边读入一边统计,并且要去掉标点符号,以空白分离单词。
要找高频词汇,肯定是要所有的单词都要遍历一次的,关键就是怎么遍历了。为了时间效率高一点,可以采用类似二叉排序树的方法,单词以字母为序,比如abc排在edf前面,也排在acd前面。
每读入一个词就进行二叉树排序树的查找操作,找到了节点的统计字段加1,找不到插入。其次,还要维护大小为10数组存储当前出现次数最高的词和它们的出现次数,按降序排列。每在二叉排序树中成功查找到该次,更新该词的出现次数后,与前10数组进行比较,如果这个词已经出现前10数组那就直接更新对应的值,如果这个词没有出现,则删除最有一个,然后插入。
伪代码:
先定义几个数据结构:
typedef struct{
int count=0; //统计出现次数
string content=''; //单词的拼写
} word;
typedef struct{ //二叉排序树的一个节点的结构
word node:null; //单词的统计
biNode *left:null; //左孩子
biNode *right:null; //右孩子
} biTNode,*biTree;
word topTenWord[1..10] ; //记录当前出现次数最高的10单词,按照从高到低排序,初始每个元素内容为word{null,0};
假设二叉树的查找算法search已经实现,查找成功更新词的出现次数不成功插入,返回插入的点或是找到的点。
算法
word[10] Count(filename){
//输入:文件的名称
//输出:前十的词频的数组
binaryTree=createBinaryTree(); //先建立一个二叉排序树
totalWordCount=0; //文章里面的单词数
firstWorld= readfrom(filename);
topTenWord[1]={firstWorld,1}; //先把第一个词读入,这样可以避免越界检查
while(oneword=readfrom(filename)){ //读入词
totalWordCount++;
biTNode *p=search(bianryTree,oneworld);
if (p.node.count>topTenWord.last.count) { //新词的出现次数比前10数组里面最小的出现次数大
//从后往前找,找到第一个比它大或者等于它的
i=10;
while(topTenWord[i].count<p.node.count) i--; //不用判断越界,因为不会越界,i最多走到1.
if (topTenWord[i].content==p.node.content){ //同一个词
topTenWord[i].count++;
}
else{
for(j=9;j>i;j--){
topTenWord[j+1]=topTenWord[j];
}
topTenWord[i+1]=p.node; //将当前单词复制过来,复制内容,不是复制指针
}
}
}
//计算频率
for (i=1;i<=10;i++) {
topTenWord[i]=topTenWord[i]/totalWordCount;
}
return topTenWorld;
}
时间效率应该是nlog(n).