【学习笔记】C#中HashTable和快速排序的用法,从单词频率统计小程序写起
先瞎扯点别的。进入这个神圣的地方总需要些鞭策,阿西巴,我是被鞭策进来摆摊的程序猿。软件工程老师说,写程序,发博客,就来博客园。这是个号召力很强的口号。最近看网络营销 搜索引擎优化的书多一些,只能说王老师真的很厉害,至少在这一周因为这个作业的原因,我们学校的程序猿们对各大程序网站访问猛然骤增,网站流量,点击价值当然也是不菲,不过流量转化率就不好说了,当然了,三年多了都这样。再插一句,Google确实比百度做得好(其实只有中国用百度),SEO优化做的很到位,最近推出的“蜂鸟算法”也很棒,因为关键词明显好找么。
好了,言归正传了。
题目主要是写一个程序,分析一个文本文件(英文文章)中各个词出现的频率,并且把频率最高的10个词打印出来。
自从周四拿到题目以后,发现又要用到万恶的数据结构了,不得不说这是我的短板,所有上周20号到22号一直在看数据结构的书,当然还有google,在看书的期间确定了这个小程序编码的思路。
1.首先进行文本文件的读取,将一个一个的单词分离出来,并对单词进行统计;
2.然后对单词出现的次数进行排序;
3.最后把频率最高的10个词打印出来。
整理好思路以后,在23号的中午我终于准备拯救世界了,当然,我们宿舍的其他三位大神已经写完。。好了,不提我伤心的事了~~
经过分析后,主要就是解决两个算法的问题,
(1).查找问题:统计出所有出现的单词以及他们出现的次数,这个方法挺多的,这次主要用了Hashtable,速度快,方便。
在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似keyvalue的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中keyvalue键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对.
下面的代码getAllWords和CountWord分别统计出了所有出现的单词以及他们出现的次数。并且用控制台和文件输出两种方式输出。
1.首先是计算单词的次数。
这里主要用到Hashtable 中各元素的虚拟子组存储桶,每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键key.并且把分割的所有的单词存放到一个名为List<WordInfo>的集合类中,最后用allWordInfos.Add(new WordInfo(key, (int)allWords[key]));在哈希表中添加了一个keyvalue键值对,为每一唯一键生成唯一哈希代码的哈希函数使得搜索性能更佳。
public void CountWord(string inputFilePath, string outputFilePath)
{
Hashtable allWords = getAllWords(inputFilePath);
List<WordInfo> allWordInfos = new List<WordInfo>();
foreach (string key in allWords.Keys)
{
allWordInfos.Add(new WordInfo(key, (int)allWords[key]));
}
qucikSort(allWordInfos, , allWordInfos.Count - );
writeToFile(allWordInfos, outputFilePath);
}
2.然后是统计出了所有出现的单词
在分析过程中发现还需要特别注意' ', ',', ';', '.', '!', '"'这些符号,所以在读取字节的时候用到了StreamReader的方法,主要是使其以一种特定的编码从字节流中读取字节。然后将读出来的字符串做处理,分成一个个的单词,然后就把所有英文单词对象添加到 Hashtable 的存储桶中,该存储桶与匹配该对象的哈希代码的哈希代码关联。在 Hashtable 内搜索一个值时,将为该值生成哈希代码,并且搜索与该哈希代码关联的存储桶。使得搜索效率变得很高。
private Hashtable getAllWords(string filePath)
{
Hashtable allWords = new Hashtable();
using (StreamReader sr = new StreamReader(filePath, Encoding.Default))
{
string line = null; char[] seperators = new char[] { ' ', ',', ';', '.', '!', '"' };
string[] words = null;
while ((line = sr.ReadLine()) != null)
{
line = line.ToLower();
words = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries);
if (words != null && words.Length > )
{
for (int i = ; i < words.Length; i++)
{
if (allWords.ContainsKey(words[i]))
{
allWords[words[i]] = (int)allWords[words[i]] + ;
}
else
{
allWords.Add(words[i], );
}
}
}
}
}
return allWords;
}
这个程序第二个问题就是
(2)排序问题,在这里用到了快速排序。
具体思路就是
1.分别设置low、hight指向序列的最左端、最右端;从序列中选一个进行排序(通常选最左端的值low指向的值),存入到value;
2.从hight端开始,查找比value小的,找到后讲该值放入到low指向的存储位中;同时将hight指向当前查到的值所在的位;
3.从low端开始,查找比value大的,找到后将该值放入到hight指向的存储为中,同时low指向当前查到的值所在位;
4.若low位小于hight位,返回2步;否则,将tmp值存入到空出来的low+1指向的位置,退出,返回low所在的位置lposition。
5.以lposition为界,将序列分成两部分,分别对两部分进行排序。
找了图,呵呵O(∩_∩)O~ 神一样的图~~

private void qucikSort(List<WordInfo> allWordInfos, int low, int high)
{
if (low >= high)
{
return;
}
int pLow = low;
int pHigh = high;
WordInfo value = allWordInfos[low];
while (pLow < pHigh)
{
while ((WordInfo.Compare(allWordInfos[pHigh], value) <= ) && pHigh > pLow)
{
pHigh--;
}
if (WordInfo.Compare(allWordInfos[pHigh], value) > )
{
allWordInfos[pLow] = allWordInfos[pHigh];
allWordInfos[pHigh] = value;
pLow++;
}
while ((WordInfo.Compare(allWordInfos[pLow], value) >= ) && pHigh > pLow)
{
pLow++;
}
if (WordInfo.Compare(allWordInfos[pLow], value) <)
{
allWordInfos[pHigh] = allWordInfos[pLow];
allWordInfos[pLow] = value;
pHigh--;
}
}
System.Diagnostics.Trace.Assert(pLow == pHigh);
qucikSort(allWordInfos, low, pLow - );
qucikSort(allWordInfos, pLow + , high);
}
此次快速排序可以将英文单词出现的频率全部从高到低排序出来存储在哈希表的存储桶里。
小插曲:在解决快速排序算法的时候,要感谢我们宿舍的各位亲们,编码抓狂的时候有你们足以O(∩_∩)O~ @我编程我快乐 @韩亚华 @FakerWang
最后再解决一些小问题
(3)控制台输出,文本输入输出,以及遍历出频率最高的10个词打印出来等问题。
private void writeToFile(List<WordInfo> allWordInfos, string outputFilePath)
{
using (StreamWriter sw = new StreamWriter(outputFilePath, false, Encoding.Default))
{
int i = ;
sw.WriteLine("单词频率最高的10个词统计如下");
foreach (WordInfo wi in allWordInfos)
{
sw.WriteLine("{0}:{1}", wi.Word, wi.Count);//输出到文本文件
Console.WriteLine("{0}:{1}", wi.Word, wi.Count);//输出到控制台
i++;
if (i == ) break;
}
}
}
行了,差不多了,截图纪念了。。

个人小项目总结:
最后总结下Hashtable的简单操作吧
1.在哈希表中添加一个keyvalue键值对:HashtableObject.Add(key,value);
2.在哈希表中去除某个keyvalue键值对:HashtableObject.Remove(key);
3.从哈希表中移除所有元素: HashtableObject.Clear();
4.判断哈希表是否包含特定键key: HashtableObject.Contains(key);
以后肯定还得用。
这个小程序到这里也就结束了,也就是24号到27号,水平有限没办法。不过还是有个好玩的小插曲的,做完以后才发现我的运行效率是宿舍最快的,我们一起运行了一个5兆的英文文章,最慢的要20秒,我的3秒搞定,阿西巴,这是开挂的节奏啊,好了,差不多睡了,晚安了,各位程序猿和程序媛们~~

【学习笔记】C#中HashTable和快速排序的用法,从单词频率统计小程序写起的更多相关文章
- C#中HashTable和快速排序的用法
题目主要是写一个程序,分析一个文本文件(英文文章)中各个词出现的频率,并且把频率最高的10个词打印出来. 自从周四拿到题目以后,发现又要用到万恶的数据结构了,不得不说这是我的短板,所有上周20号到 ...
- ArcGIS案例学习笔记-点集中最近点对和最远点对
ArcGIS案例学习笔记-点集中最近点对和最远点对 联系方式:谢老师,135-4855-4328,xiexiaokui@qq.com 目的:对于点图层,查找最近的点对和最远的点对 数据: 方法: 1. ...
- 《Cocos2d-x游戏开发实战精解》学习笔记3--在Cocos2d-x中播放声音
<Cocos2d-x游戏开发实战精解>学习笔记1--在Cocos2d中显示图像 <Cocos2d-x游戏开发实战精解>学习笔记2--在Cocos2d-x中显示一行文字 之前的内 ...
- Ext.Net学习笔记19:Ext.Net FormPanel 简单用法
Ext.Net学习笔记19:Ext.Net FormPanel 简单用法 FormPanel是一个常用的控件,Ext.Net中的FormPanel控件同样具有非常丰富的功能,在接下来的笔记中我们将一起 ...
- Ext.Net学习笔记20:Ext.Net FormPanel 复杂用法
Ext.Net学习笔记20:Ext.Net FormPanel 复杂用法 在上一篇笔记中我们介绍了Ext.Net的简单用法,并创建了一个简单的登录表单.今天我们将看一下如何更好是使用FormPanel ...
- Ext.Net学习笔记12:Ext.Net GridPanel Filter用法
Ext.Net学习笔记12:Ext.Net GridPanel Filter用法 Ext.Net GridPanel的用法在上一篇中已经介绍过,这篇笔记讲介绍Filter的用法. Filter是用来过 ...
- Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法
Ext.Net学习笔记13:Ext.Net GridPanel Sorter用法 这篇笔记将介绍如何使用Ext.Net GridPanel 中使用Sorter. 默认情况下,Ext.Net GridP ...
- Ext.Net学习笔记14:Ext.Net GridPanel Grouping用法
Ext.Net学习笔记14:Ext.Net GridPanel Grouping用法 Ext.Net GridPanel可以进行Group操作,例如: 如何启用Grouping功能呢?只需要在Grid ...
- Ext.Net学习笔记11:Ext.Net GridPanel的用法
Ext.Net学习笔记11:Ext.Net GridPanel的用法 GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: < ...
随机推荐
- div固定在屏幕底部
项目中需要实现div一直显示在屏幕的底部,不管页面有多长或者多端都需要满足. 在网上找的用js实现的,移动时会闪动,效果不是特别好.也可能是没找到好的. 相比js,我更希望使用css实现 1 < ...
- UISearchController,SearchBar的教程-Swift
如果你的应用程序里显示了大量的数据,滚动的查看大规模的列表会很慢,也会给人一种烦躁的感觉.在这种情况下,查询UISearchController, UISearchBar是极其重要的,可以让用户搜索特 ...
- BZOJ1875 [SDOI2009]HH去散步 【dp + 矩阵优化】
题目 HH有个一成不变的习惯,喜欢饭后百步走.所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离. 但 是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回. 又因为HH是个喜欢变 ...
- 【CCF】有趣的数 数位dp
[思路] dp[i][j]表示前i个数为第j种状态,考虑6种状态 0: 出现且仅出现 2 1: 出现且仅出现 2 0 2: 出现且仅出现 2 3 3: 出现且仅出现 2 0 1 4: 出现且仅出现 2 ...
- PHP读取APK的包信息,包括包名,应用名,权限,LOGO等
[转]PHP读取APK的包信息,包括包名,应用名,权限,LOGO等 声明本文转自: 原文链接:https://www.jb51.net/article/53780.htm: 感谢分享! <?ph ...
- 关于Dijkstra 和 Bellman-ford算法的简单理解
两个算法都是跟求图的有源最短路径有关.Dijkstra主要针对的是无负权值节点的图,而Bellman-Ford算法则是可以处理有负权值的有向图的最短路径问题.两者都用到了一个“松弛计算”的方法,也就是 ...
- LeetCode OJ——Two Sum
http://oj.leetcode.com/problems/two-sum/ 求是否存在两个数的和为target,暴力法,两层循环 #include <iostream> #inclu ...
- AC日记——最大子树和 洛谷 P1122
题目描述 小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题.一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题.于是当日课后,小明 ...
- 设计模式原来如此-策略模式(Strategy Pattern)
策略模式中体现了两个非常基本的面向对象设计的原则:1.封装变化的概念.2.编程中使用接口,而不是对接口的实现. 策略模式的定义:定义一组算法,将每个算法都封装起来,并使它们之间可以互换.策略模式使这些 ...
- Codeforces 558E A Simple Task(权值线段树)
题目链接 A Simple Task 题意 给出一个小写字母序列和若干操作.每个操作为对给定区间进行升序排序或降序排序. 考虑权值线段树. 建立26棵权值线段树.每次操作的时候先把26棵线段树上的 ...