本文的很多内容来自网络。如有错误,欢迎指出。

问题描写叙述

首先这里对单词的界定是:以空白切割的字符序列。

单词统计的问题能够描写叙述为:在一篇正常格式的英文文档中(作为面试。这里并没有提及中文分词和单词统计的问题),统计每一个单词出现的次数。要求统计出现次数最多的N个单词和对应的出现次数。

问题简单明了。无需对字面做很多其它的解释。

为什么面试官都喜欢考诸如此类的问题?

这类问题,大都有一个共同点:不仅要考虑数据的存储,并且要考虑排序的问题。更重要的是。普通方法能够解,偏偏面试官要找性能最好的、形式最优雅的。

怎么解?

细致研读一下题目,发现事实上仅仅有三件事情要做:1.单词次数统计 2. 排序。

3.输出前N个,当中问题3仅仅是问题2的衍生,因此能够忽略。进一步分析发现,事实上这是典型的TOP K问题。抛开TOP K问题的经典解决方式不提,我们先看看一步步来看问题的解决思路。

1. Map

C++ Standard Template Library中提供了一种高效的容器Map, 它是一种键值对容器(关联容器),因此能够轻松存储<单词, 次数>这种键值序列,因而,最简洁的解决方式能够是这种:

int main(void){Map <String , int> wc;Map <String , int>::iterator j;String w;while( cin >> w ){wc[ w ] ++;}for( j = wc.begin(); j != wc.end(); j++ ){count << j->first <<  " : " j->second << "\n";}return 0;
}

因为Map的特性(数据插入时保证有序),因此输出的结果事实上是依照key(也就是单词)排好序的。所以,还须要对输出的结果进行排序。至于怎么排序,sort。qsort,还是自建heap sort。不再赘述。

这样已经非常好了,Map容器本身内建红黑树,使得插入的效率非常高。

可是,这样真的好吗?别忘了,面试官的要求更高。

2. Hashtable 神器。一键直达。效率再快一点

对于单词和单词次数的映射,除了使用Map外,还能够使用自己定义的hash表,hash表的节点应该包含三个主要的域:指向单词的指针或String,单词的出现次数int。指向下一个节点的指针node *。

如果我们处理hash冲突的方案是链地址法。则:

Hash表node的定义为:

typedef struct node{char * word;int  count;node * next;
} node;

再次如果,处理的独立的单词个数不超过5w, 因此能够选择50021 这个质数作为hash表的大小。而hash算法。我们能够选择经常使用的BKDR算法(以31为累乘因子),这样。能够将单词映射为一个unsigned int的整数:

#define HASH_SIZE 50021;
#define MUL_FACTOR 31;
node* mmap[HASH_SIZE];unsigned int hashCode( char *p){unsigned int result = 0;while(*p != '\0' ){result = result * MUL_FACTOR + *p++;}return result % HASH_SIZE;
}

函数wordCount( char *p )用于将单词和单词的出现次数插入hash表中,假设hash表中有对应的节点,则添加单词的次数并返回,否则须要加入新的节点到hash表的表头并初始化次数为1.

 1 void wordCount( char *w ){
 2     unsigned int hashCode = hash( p );
 3     node * p;
 4
 5     while( p = mmap[hashCode];p!=NULL;p = p->next ){
 6         if(strcmp(w, p->word) == 0){
 7             (p->count)++;
 8             return ;
 9         }
10     }
11
12     node*q = (node*) malloc(sizeof(node));
13     q->count = 1;
14     q->word = (char *) malloc(sizeof(w) + 1);
15     strcpy(q->word, w);
16     q->next = mmap[hashCode];
17     mmap[hashCode] = q;
18 }

相同,hash表仅仅是提供了数据存储。并没有排序。排序的问题,还须要你来完毕。

这样似乎就完美了。

可素。伦家既不懂算法,又不会C++的容器。肿么办 ?

3.  Shell版本号的单词统计

Linux提供了非常多文本操作的工具。比方uniq, tr ,sort。而管道的存在,恰到优点的攻克了文本和单词及中间处理结果须要存储的问题。最重要的一点,这些工具是一系列的黑盒,你仅仅须要知道怎样使用,而大不必去在乎内部实现的细节。

对于本题。用Linux 工具去处理,命令能够是:

cat  word |
tr –cs a-zA-Z\’ ‘\n’ |
tr A-Z a-z |
sort |
uniq –c |
sort –k1,1nr |
head –n 10

对该程序每一行的解释:

  1. cat word                将word文件的内容读入缓存区。并作为下一个命令的输入
  2. tr –cs a-zA-Z\’ ‘\n’   将非字母字符转换为换行符,保证一行一个单词
  3. tr A-Z a-z              将全部单词转为小写形式。保证and和And是同一个单词
  4. sort                       按单词排序
  5. uniq –c                  统计每一个单词的反复次数,也就相当于单词的出现次数
  6. sort –k1,1nr            依照出现次数排序逆序排序。-n指定数字比較。-r指定逆序排序
  7. head –n 10             输出出现次数最多的10个单词和它们的出现次数

写到这里,突然想起若干年前去百度面试的时候。一个技术T5的大拿问的问题,也就是这道单词统计的问题:一个文本中包括了非常多单词,每行一个单词,怎样统计每一个单词的次数?极其小白的我毫不含糊的回答:PHP脚本中每次读一行。用关联数组存单词和单词次数…….结果必定是慘烈的。

4.    文本处理的利器-AWK

既然提到了linux工具,那就不得不提一下awk(ɔk), awk是一个强大的文本分析处理工具。

Wiki上如是说:

AWK是一种优良的文本处理工具,Linux及Unix环境中现有的功能最强大的数据处理引擎之中的一个。AWK提供了极其强大的功能:能够进行正則表達式的匹配。样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。

它具备了一个完整的语言所应具有的差点儿全部精美特性。

尽管仅是溢美之词,可是不得不承认awk确实非常强大。

awk -F ' |,'
'{for(i=1; i<=NF;i++){a[tolower($i)]++;}
}END{for(i in a)print i, a[i] |"sort -k2,2nr";
}'  word

gawk 3.1+中。能够使用内置函数asort和asorti对数组进行排序,只是排序的功能较弱。

比如asort(a) ,若a是关联数组。asort的行为是仅仅对值排序,而键将被丢弃,取而代之的是新的1-n的数字索引。这能够通过自己定义排序函数的方式或者结果通过管道传递给系统sort排序解决。

5.   数据库版本号的方案。

我们这里如果文本已经是一行一个单词。

数据库表的基本结构为:

CREATE TABLE `test` (`word` varchar(20) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=gbk;

单词入库(也能够load data in file):

awk '
BEGIN{sql="insert into test(word) values ";mysql="mysql -hxxxxxx -uxxxxx -pxxx test -e ";
}{for(i=1;i<=NF;i++){sq="\"" sql "('\''" $i"'\'')" "\"";print mysql sq |"sh -x";}
}' word

那么简单的查询:

select word,count(word) as total from test group by word order by total desc;

就能够得到单词的次数。

这样的方法非常easy,由于数据库替你完毕了全部统计和排序的工作,这也是为什么非常多人一旦有什么需求就求助于数据库。

基于Key-Value的缓存系统(Redis等)也能够完毕排序的功能。这里不再赘述。

思考

假设你是面试官。你看好哪一种解法?算法和数据结构的。还是shell的,awk的。

就我而言,我觉得面试是挑选人才的。而不是靠所谓的“奇技淫巧”去为难别人的。

假设是我,看到有人用了shell的方式,或者awk的方式。我会给他高分。尽管算法是王道,但真的须要“一切从源代码做起”么?

參考文献:
1. http://www.cnblogs.com/ggjucheng/archive/2013/01/13/2858470.html
2.《shell脚本指南》
3.《编程珠玑》

转载于:https://www.cnblogs.com/gccbuaa/p/7172407.html

从单词统计问题看面试相关推荐

  1. C语言怎么实现单词下落,如何用c语言实现单词统计

    如何用c语言实现单词统计 输入一串字符串,输出其中有多少个单词. 代码如下:#include #include #define SIZE 20 int main(){ char str[SIZE]={ ...

  2. 超大容量文本的单词统计(洛谷P1308题题解,Java语言描述)

    题目要求 P1308题目链接 分析 这题本身的话,题意就挺烦人,下面分析一下. 本题标签"高性能",再看看数据范围,暴力匹配必死无疑.我讨厌用char[]慢慢墨迹,Java操作这个 ...

  3. 大数据阶段划分及案例单词统计

    大数据阶段的重要课程划分 离线分析 : hadoop生态圈 HDFS, MapReduce(概念偏多), hive(底层是MapReduce), 离线业务分析80%都是使用hive实时分析 : spa ...

  4. c语言文件加密解密单词统计,C语言文件加密解密及单词统计程序.doc

    C语言文件加密解密及单词统计程序.doc (10页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 15.9 积分  高级语言程序设计 课程设计学 院 计算 ...

  5. Hadoop经典案例——单词统计

    通过 Hadoop经典案例--单词统计,来演示 Hadoop集群的简单使用. (1)打开 HDFS 的 UI,选择Utilities→Browse the file system查看分布式文件系统里的 ...

  6. python数学基础——单词统计

    这个练习使用的是英文的单词统计,使用split通过单词中间的空格来做区分,在遍历的过程中通过对[字典]类型进行[字典推导式]的处理来计算每个单词出现的频次.但是由于过程中我们通过re的正则表达式来替换 ...

  7. MapReduce之单词统计

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 MapReduce单词统计 一.搭建环境 二.编写WordCount程序 1.在IDEA中引入所需的jar包,IDEA支持文件夹方式引 ...

  8. 文本文件单词统计(C语言)

    文本文件单词统计(C语言) 本人目前还是一位在校大学生,写文章的目的是为了记录一下当前所学,与其他爱好者或从业者相互学习交流.文本文件单词统计这个题目是学校的一次课程设计中的一道,在编写时也是参考了很 ...

  9. spark 集群单词统计_最近Kafka这么火,聊一聊Kafka:Kafka与Spark的集成

    Spark 编程模型 在Spark 中, 我们通过对分布式数据集的操作来表达计算意图 ,这些计算会自动在集群上 井行执行 这样的数据集被称为弹性分布式数据集 Resilient Distributed ...

最新文章

  1. 编译cegcc 0.59.1
  2. C++中sizeof问题
  3. 将近一半的用户希望能够在两秒内或者更短的时间内打开网站
  4. 用linux装逼-我的vim配置(不定时更新)
  5. 音乐文件基本格式,wave,mod,midi,mp3,wma,flac
  6. SDNU 1019.礼物(水题)
  7. js求渐升数的第100位
  8. ARC_xp_20160526
  9. 面向对象编程(三)——程序执行过程中内存分析
  10. 13个Python小游戏(含源码),开始敲起来,玩吧!
  11. win11系统下安装java 8的教程
  12. 微软私有云系列 ----SQL 云部署
  13. 秒懂,Java 注解 (Annotation)你可以这样学
  14. 易简无人机巡检照片处理系统(一) —— 巡检作业流程
  15. python查询mysql decimal报错_【2020Python修炼记】MySQL之 表相关操作
  16. 13 信息2班 《安卓程序设计基础》课程成绩
  17. 微电子电路——期中总结
  18. 有一位后代曾忏悔:他的祖父继承家里的淫业,到了他父亲那一代,果报现前
  19. 对SingleTask和TaskAffinity的理解
  20. java程序运行机制

热门文章

  1. 简单图文配置golang+vscode【win10/centos7+golang helloworld+解决install failed等情况】
  2. 2022-2028年中国高纯锑行业市场全景研究及发展趋势分析报告
  3. Python 典型错误及关键知识点
  4. 朴素贝叶斯与逻辑回归区别
  5. 矩阵乘以其矩阵转置求导-数学
  6. Python __dict__属性详解
  7. LeetCode简单题之托普利茨矩阵
  8. C语言与OpenCL的编程示例比较
  9. 软件定义汽车:本质并行化的有效平台
  10. CVPR2020论文解读:手绘草图卷积网络语义分割