题目主要是写一个程序,分析一个文本文件(英文文章)中各个词出现的频率,并且把频率最高的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键值对托福答案 www.qcwy123.com 下面的代码getAllWords和CountWord分别统计出了所有出现的单词以及他们出现的次数。并且用控制台和文件输出两种方式输出。 1.首先是计算单词的次数。 这里主要用到Hashtable 中各元素的虚拟子组存储桶,每一存储桶都与一个哈希代码关联,该哈希代码是使用哈希函数生成的并基于该元素的键key.并且把分割的所有的单词存放到一个名为List<WordInfo>的集合类中,最后用allWordInfos.Add(new WordInfo(key, (int)allWords[key]));在哈希表中添加了一个keyvalue键值对,为每一唯一键生成唯一哈希代码的哈希函数使得搜索性能更佳。 1 public void CountWord(string inputFilePath, string outputFilePath) 2 { 3 Hashtable allWords = getAllWords(inputFilePath); 4 List<WordInfo> allWordInfos = new List<WordInfo>(); 5 foreach (string key in allWords.Keys) 6 { 7 allWordInfos.Add(new WordInfo(key, (int)allWords[key])); 8 } 9 qucikSort(allWordInfos, 0, allWordInfos.Count - 1); 10 writeToFile(allWordInfos, outputFilePath); 11 } 2.然后是统计出了所有出现的单词 在分析过程中发现还需要特别注意' ', ',', ';', '.', '!', '"'这些符号,所以在读取字节的时候用到了StreamReader的方法,主要是使其以一种特定的编码从字节流中读取字节。然后将读出来的字符串做处理,分成一个个的单词,然后就把所有英文单词对象添加到 Hashtable 的存储桶中,该存储桶与匹配该对象的哈希代码的哈希代码关联。在 Hashtable 内搜索一个值时,将为该值生成哈希代码,并且搜索与该哈希代码关联的存储桶。使得搜索效率变得很高托福答案 www.tfjy386.com 1 private Hashtable getAllWords(string filePath) 2 { 3 Hashtable allWords = new Hashtable(10240); 4 using (StreamReader sr = new StreamReader(filePath, Encoding.Default)) 5 { 6 string line = null; 7 8 char[] seperators = new char[] { ' ', ',', ';', '.', '!', '"' }; 9 string[] words = null; 10 while ((line = sr.ReadLine()) != null) 11 { 12 line = line.ToLower(); 13 words = line.Split(seperators, StringSplitOptions.RemoveEmptyEntries); 14 if (words != null && words.Length > 0) 15 { 16 for (int i = 0; i < words.Length; i++) 17 { 18 if (allWords.ContainsKey(words[i])) 19 { 20 allWords[words[i]] = (int)allWords[words[i]] + 1; 21 } 22 else 23 { 24 allWords.Add(words[i], 1); 25 } 26 } 27 } 28 } 29 } 30 return allWords; 31 } 这个程序第二个问题就是 (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~ 神一样的图~~ 1 private void qucikSort(List<WordInfo> allWordInfos, int low, int high) 2 { 3 if (low >= high) 4 { 5 return; 6 } 7 int pLow = low; 8 int pHigh = high; 9 WordInfo value = allWordInfos[low]; 10 while (pLow < pHigh) 11 { 12 while ((WordInfo.Compare(allWordInfos[pHigh], value) <= 0) && pHigh > pLow) 13 { 14 pHigh--; 15 } 16 if (WordInfo.Compare(allWordInfos[pHigh], value) > 0) 17 { 18 allWordInfos[pLow] = allWordInfos[pHigh]; 19 allWordInfos[pHigh] = value; 20 pLow++; 21 } 22 while ((WordInfo.Compare(allWordInfos[pLow], value) >= 0) && pHigh > pLow) 23 { 24 pLow++; 25 } 26 if (WordInfo.Compare(allWordInfos[pLow], value) <0) 27 { 28 allWordInfos[pHigh] = allWordInfos[pLow]; 29 allWordInfos[pLow] = value; 30 pHigh--; 31 } 32 } 33 System.Diagnostics.Trace.Assert(pLow == pHigh); 34 qucikSort(allWordInfos, low, pLow - 1); 35 qucikSort(allWordInfos, pLow + 1, high); 36 } 此次快速排序可以将英文单词出现的频率全部从高到低排序出来存储在哈希表的存储桶里。 小插曲:在解决快速排序算法的时候,要感谢我们宿舍的各位亲们,编码抓狂的时候有你们足以O(∩_∩)O~ @我编程我快乐 @韩亚华 @FakerWang 最后再解决一些小问题 (3)控制台输出,文本输入输出,以及遍历出频率最高的10个词打印出来等问题。 1 private void writeToFile(List<WordInfo> allWordInfos, string outputFilePath) 2 { 3 using (StreamWriter sw = new StreamWriter(outputFilePath, false, Encoding.Default)) 4 { 5 int i = 0; 6 sw.WriteLine("单词频率最高的10个词统计如下"); 7 foreach (WordInfo wi in allWordInfos) 8 { 9 sw.WriteLine("{0}:{1}", wi.Word, wi.Count);//输出到文本文件 10 Console.WriteLine("{0}:{1}", wi.Word, wi.Count);//输出到控制台 11 i++; 12 if (i == 10) break; 13 } 14 } 15 }
|
请发表评论