github项目地址 | 做业项目地址 |
---|---|
结对编程伙伴博客地址 | 做业要求连接 |
做业要求地址 | 做业要求地址 |
(1)PSP表格html
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
· Estimate | · 估计这个任务须要多少时间 | 30 | 30 |
Development | 开发 | 770 | 720 |
· Analysis | · 需求分析 (包括学习新技术) | 300 | 240 |
· Design Spec | · 生成设计文档 | 30 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 20 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 20 | 15 |
· Design | · 具体设计 | 30 | 30 |
· Coding | · 具体编码 | 300 | 315 |
· Code Review | · 代码复审 | 30 | 40 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 40 |
Reporting | 报告 | 150 | 120 |
· Test Report | · 测试报告 | 60 | 45 |
· Size Measurement | · 计算工做量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 过后总结, 并提出过程改进计划 | 60 | 45 |
合计 | 950 | 900 |
(2)代码规范:node
命名规范:1.类名首字母要大写,使用可以反映类功能的名词或名词短语命名类。git
2.类成员变量首单词小写,变量名前可加_前缀。github
3.方法名第一个字符要大写,且应使用动词或动词短语。编程
4.参数首字符小写,采用描述性参数名称。函数
5.接口名称要有意义,接口修饰符只能用public和internal。性能
6.每条语句至少占一行,过长语句断为两行显示。学习
7.语句嵌套不超过3层。测试
详细代码规范见:[代码规范this
结对过程:
emmm 真香。
结对编程的照片:
因为二人对C#都并不熟悉,解题思路就是百度,每遇到一个问题就查,编写边学。
参考做业要求咱们将项目目标归纳为以下几点:
统计词频、字符数、行数
public class WordCalculate { public long charactersnumber = 0; //字符数 public long wordsnumber = 0; //单词数 public long linesnumber = 0; //行数 public long phrasenumber = 0; //词组数 //数据统计 public void Calculate(string dataline, WordTrie wtrie) { if (string.IsNullOrEmpty(dataline)) return; string word = null; for (int i = 0, len = dataline.Length; i < len; i++) { char unit = dataline[i]; if (unit >= 65 && unit <= 90){ unit = (char)(unit + 32); } //大写转小写 if ((unit >= 48 && unit <= 57) || (unit >= 97 && unit <= 122)){ word = String.Concat(word, unit); } else{ if (!string.IsNullOrEmpty(word)){ //判断是否为词尾后的字符 if (word[0] >= 97 && word[0] <= 122){ //首字符是否为字母 wtrie.Insert(word); } word = null; } } } if (!string.IsNullOrEmpty(word)) //判断行尾是否有单词 { if (word[0] >= 97 && word[0] <= 122){ //首字符是否为字母 wtrie.Insert(word); } word = null; } this.linesnumber++; //统计行数 this.wordsnumber += wtrie.CountSum; //统计单词数 this.charactersnumber += dataline.Length; //统计字符数 } }
读取文件
public WordCalculate Input(WordCalculate datanumber, WordTrie wtrie) { FileStream fs = null; StreamReader sr = null; String dataline = String.Empty; try { fs = new FileStream(this.pathIn, FileMode.Open); sr = new StreamReader(fs); while ((dataline = sr.ReadLine()) != null) { datanumber.Calculate(dataline, wtrie); //按行统计数据 } } catch { Console.WriteLine("文档读取失败!"); } finally { if (sr != null) { sr.Close(); } if (fs != null) { fs.Close(); } } return datanumber; }
文件写入
public void Output(WordCalculate datanumber, WordTrie wtrie,int n) { FileStream fs = null; StreamWriter sw = null; List<WordTrie.ListUnit> WordList = new List<WordTrie.ListUnit>(); try { fs = new FileStream(this.pathOut, FileMode.Create); sw = new StreamWriter(fs); WordList = wtrie.Sort(); sw.WriteLine(String.Concat("characters:", datanumber.charactersnumber, "\n")); sw.WriteLine(String.Concat("words:", datanumber.wordsnumber, "\n")); sw.WriteLine(String.Concat("lines:", datanumber.linesnumber, "\n")); sw.WriteLine("\n词频\t单词\n"); Console.WriteLine(String.Concat("characters:", datanumber.charactersnumber)); Console.WriteLine(String.Concat("words:", datanumber.wordsnumber)); Console.WriteLine(String.Concat("lines:", datanumber.linesnumber, "\n")); //Console.WriteLine("\n词频\t单词\n"); for (int i = 0; (i < n && i < datanumber.wordsnumber); i++) { sw.WriteLine(WordList[i].Word + ":" + String.Concat(WordList[i].WordNum)); Console.WriteLine(WordList[i].Word+":"+String.Concat(WordList[i].WordNum)); } } //catch { Console.WriteLine("文档写入失败!"); } finally { if (sw != null) { sw.Close(); } if (fs != null) { fs.Close(); } } }
利用Trie树统计词频
(按理说用字典类更好作的······ trie统计词频的效率会更高一点,可是彻底没有办法写词组,最后仍是向字典类底头···)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wordCount { class WordTrie { //Trie树节点 private class TrieNode { public int PrefixNum = 0; //前缀词频 public int WordNum = 0; //词频 public Dictionary<char, TrieNode> Sons = new Dictionary<char, TrieNode>(); //子节点 public bool IsEnd = false; //是否可为终节点 public char Val; //节点值 public string Word = null; //单词值 //构造函数 public TrieNode() { } public TrieNode(char val) { Val = val; } } private TrieNode _Root = new TrieNode(); //全部单词词频总和 public int CountSum { get { return _Root.PrefixNum; } } //插入单词 public void Insert(string word) { if (string.IsNullOrEmpty(word)) return; TrieNode node = _Root; node.PrefixNum++; for (int i = 0, len = word.Length; i < len; i++) { char pos = word[i]; if (!node.Sons.ContainsKey(pos)) { node.Sons[pos] = new TrieNode(pos); } node.Sons[pos].PrefixNum++; node = node.Sons[pos]; } node.Word = word; node.IsEnd = true; node.WordNum++; } //获取前缀词频 public int PrefixCount(string prefix) { return GetCount(prefix, false); } //获取单词词频 public int WordCount(string word) { return GetCount(word, true); } private int GetCount(string str, bool isword) { if (string.IsNullOrEmpty(str)) return -1; TrieNode node = _Root; for (int i = 0, len = str.Length; i < len; i++) { char pos = str[i]; if (!node.Sons.ContainsKey(pos)) return 0; else node = node.Sons[pos]; } return isword ? node.WordNum : node.PrefixNum; } //是否包含指定的单词 public bool ContainsWord(string word) { return WordCount(word) > 0; } //单词表单元 public class ListUnit { public string Word; //单词 public int WordNum; //词频 } //词频排序 public List<ListUnit> Sort() { TrieNode node = _Root; List<ListUnit> WordList = new List<ListUnit>(); WordList = WordPreOrder(node, WordList); //按词频降序排列,若词频相等按字典序排列 WordList.Sort((a, b) => { if (a.WordNum.CompareTo(b.WordNum) != 0) return -a.WordNum.CompareTo(b.WordNum); else return a.Word.CompareTo(b.Word); }); return WordList; } //单词表生成(Trie树的前序遍历) private List<ListUnit> WordPreOrder(TrieNode node, List<ListUnit> WordList) { if (node.PrefixNum == 0) { return WordList; } if (node.WordNum != 0) { ListUnit unit = new ListUnit(); unit.Word = node.Word; unit.WordNum = node.WordNum; WordList.Add(unit); } foreach (char key in node.Sons.Keys) { WordList = WordPreOrder(node.Sons[key], WordList); } return WordList; } } }
关于Tire树的相关参考以下:字典树(trie树)实现词频查找
详见我队友写的博客
传送门