C# 词典数据结构设计【附demo】
分析
要建立词典,最基本的应该有词典的描述信息、词典索引文件以及词典数据文件。
/// <summary>
/// 索引文件
/// </summary>
string idxFile = "dic.idx";/// <summary>
/// 数据文件
/// </summary>
string dictfile = "dic.dict";/// <summary>
/// 词典信息文件
/// </summary>
string ifoFile = "dic.ifo";我们建立对应的三个类
详细的代码如下:
/// /// 词语解释/// class DictWord{/// /// 解析/// public string Description{get;set;}}/// /// 词典索引/// class DictIndex{/// /// 词语/// public string Word{get;set;}/// /// 偏移/// public int Offset{get;set;}/// /// 数据大小/// public int DataSize{get;set;}}/// /// 词典信息/// class DictInfo{/// /// 词典名称/// public string BookName{get;set;}/// /// 收录词数/// public int WordCount{get;set;}/// /// 当前偏移/// public int CurrentOffset{get;set;}}
数据结构说明:
- 描述信息包含词典名字,词典词语数量
- 索引文件存储的是排好顺序词语的索引,每个索引包含词语名称、存在数据文件中的偏移量、以及数据块大小,排序的目的在于查找时直接用二分查找节省查找时间。
- 数据块就简单了,就纯粹的数据
建立词典
建立词典比较简单,首先,定义几个变量来存储词典相关信息:
DictInfo info;
SortedList<string, DictIndex> indexs;
List<DictWord> words;
ps: SortedList能直接排序,不用我们再手动排序了
然后我们来看添加词语:
/// /// 添加词语/// /// /// public void Add(string word, string description){words.Add(new DictWord() { Description = description });indexs.Add(word, new DictIndex { DataSize = Encoding.UTF8.GetBytes(description).Length, Offset = info.CurrentOffset, Word = word });// 数量++info.WordCount++;// 偏移++info.CurrentOffset += Encoding.UTF8.GetBytes(description).Length;}
非常简单,就是添加索引,同时把词典的数量加1
最后来看怎么存储到文件:
/// /// 保存/// public void Save(){StringBuilder dicBuilder = new StringBuilder();dicBuilder.AppendLine(string.Format("BookName={0}", info.BookName));dicBuilder.AppendLine(string.Format("WordCount={0}", info.WordCount));dicBuilder.AppendLine(string.Format("CurrentOffset={0}", info.CurrentOffset));File.WriteAllText(ifoFile, dicBuilder.ToString(), Encoding.UTF8);dicBuilder = new StringBuilder();using (BinaryWriter idxWriter = new BinaryWriter(File.Open(dictfile, FileMode.Create))){foreach (var word in words){idxWriter.Write(Encoding.UTF8.GetBytes(word.Description));}}using (BinaryWriter idxWriter = new BinaryWriter(File.Open(idxFile, FileMode.Create))){foreach (var index in indexs){// 分块大小 128+4+4 = 136// word 最长128byte[] word = new byte[128];var wordData = Encoding.UTF8.GetBytes(index.Key);var length = Math.Min(128, wordData.Length);for (var i = 0; i < length; i++){word[i] = wordData[i];}idxWriter.Write(word);byte[] re = new byte[4];idxWriter.Write(index.Value.Offset);idxWriter.Write(index.Value.DataSize);}}}
这里注意下word最多能存128个字节,每个index区地大小为128+4+4 = 136字节
查询词典
前面做这么多准备,不都是为了查询吗?木有查询,神马都是浮云!
前面说到了,索引文件存储的是排序好的词语列表,所以查询就比较简单了
先给出两个辅助方法:
idxStream = new FileStream(idxFile, FileMode.Open);
idxReader = new BinaryReader(idxStream);
dictStream = new FileStream(dictfile, FileMode.Open);
dictReader = new BinaryReader(dictStream);(1) 获取指定位置的索引
/// /// 获取指定位置的索引/// /// /// public DictIndex GetWordIndex(int wordIndex){idxStream.Seek(0, SeekOrigin.Begin);idxStream.Seek(wordIndex * 136, SeekOrigin.Begin);byte[] word = idxReader.ReadBytes(128);var dicIndex = new DictIndex();dicIndex.Word = Encoding.UTF8.GetString(word).Replace("\0", "");dicIndex.Offset = idxReader.ReadInt32();dicIndex.DataSize = idxReader.ReadInt32();return dicIndex;}
(2)获取指定索引对应的词语解释
/// /// 获取指定词语的解释/// /// /// public string GetWordDescription(DictIndex dictIndex){dictStream.Seek(0, SeekOrigin.Begin);if (dictIndex.Offset != 0)dictStream.Seek(dictIndex.Offset, SeekOrigin.Begin);byte[] word = dictReader.ReadBytes(dictIndex.DataSize);return Encoding.UTF8.GetString(word).Replace("\0", "");}
现在开始二分查找:
/// /// 获取词语解释/// /// /// public string GetDescription(string word){var i = 0;var mid = info.WordCount / 2;var max = info.WordCount;DictIndex w = new DictIndex();while (i <= max){mid = (i + max) / 2;w = GetWordIndex(mid);if (string.Compare(w.Word, word) > 0){max = mid - 1;}else if (string.Compare(w.Word, word) < 0){i = mid + 1;}else{break;}}return "[" + w.Word + "]\n" + GetWordDescription(w);}
此部分完整代码:
/// /// 词典/// class Dict{DictInfo info;SortedList indexs;List words;/// /// 索引文件/// string idxFile = "dic.idx";/// /// 数据文件/// string dictfile = "dic.dict";/// /// 词典信息文件/// string ifoFile = "dic.ifo";BinaryReader idxReader;FileStream idxStream;BinaryReader dictReader;FileStream dictStream;/// /// 查询使用/// public Dict(){LoadDictInfo();idxStream = new FileStream(idxFile, FileMode.Open);idxReader = new BinaryReader(idxStream);dictStream = new FileStream(dictfile, FileMode.Open);dictReader = new BinaryReader(dictStream);}/// /// 创建时使用/// /// public Dict(string name){info = new DictInfo { BookName = name, WordCount = 0, CurrentOffset = 0 };indexs = new SortedList();words = new List();}/// /// 获取词语解释/// /// /// public string GetDescription(string word){var i = 0;var mid = info.WordCount / 2;var max = info.WordCount;DictIndex w = new DictIndex();while (i <= max){mid = (i + max) / 2;w = GetWordIndex(mid);if (string.Compare(w.Word, word) > 0){max = mid - 1;}else if (string.Compare(w.Word, word) < 0){i = mid + 1;}else{break;}}return "[" + w.Word + "]\n" + GetWordDescription(w);}/// /// 获取指定位置的索引/// /// /// public DictIndex GetWordIndex(int wordIndex){idxStream.Seek(0, SeekOrigin.Begin);idxStream.Seek(wordIndex * 136, SeekOrigin.Begin);byte[] word = idxReader.ReadBytes(128);var dicIndex = new DictIndex();dicIndex.Word = Encoding.UTF8.GetString(word).Replace("\0", "");dicIndex.Offset = idxReader.ReadInt32();dicIndex.DataSize = idxReader.ReadInt32();return dicIndex;}/// /// 获取指定词语的解释/// /// /// public string GetWordDescription(DictIndex dictIndex){dictStream.Seek(0, SeekOrigin.Begin);if (dictIndex.Offset != 0)dictStream.Seek(dictIndex.Offset, SeekOrigin.Begin);byte[] word = dictReader.ReadBytes(dictIndex.DataSize);return Encoding.UTF8.GetString(word).Replace("\0", "");}/// /// 添加词语/// /// /// public void Add(string word, string description){words.Add(new DictWord() { Description = description });indexs.Add(word, new DictIndex { DataSize = Encoding.UTF8.GetBytes(description).Length, Offset = info.CurrentOffset, Word = word });// 数量++info.WordCount++;// 偏移++info.CurrentOffset += Encoding.UTF8.GetBytes(description).Length;}/// /// 加载词典信息/// void LoadDictInfo(){var infos = File.ReadAllLines(ifoFile);info = new DictInfo{BookName = infos[0].Replace("BookName=", "").Trim(),WordCount = int.Parse(infos[1].Replace("WordCount=", "").Trim()),CurrentOffset = int.Parse(infos[2].Replace("CurrentOffset=", "").Trim()),};}/// /// 保存/// public void Save(){StringBuilder dicBuilder = new StringBuilder();dicBuilder.AppendLine(string.Format("BookName={0}", info.BookName));dicBuilder.AppendLine(string.Format("WordCount={0}", info.WordCount));dicBuilder.AppendLine(string.Format("CurrentOffset={0}", info.CurrentOffset));File.WriteAllText(ifoFile, dicBuilder.ToString(), Encoding.UTF8);dicBuilder = new StringBuilder();using (BinaryWriter idxWriter = new BinaryWriter(File.Open(dictfile, FileMode.Create))){foreach (var word in words){idxWriter.Write(Encoding.UTF8.GetBytes(word.Description));}}using (BinaryWriter idxWriter = new BinaryWriter(File.Open(idxFile, FileMode.Create))){foreach (var index in indexs){// 分块大小 128+4+4 = 136// word 最长128byte[] word = new byte[128];var wordData = Encoding.UTF8.GetBytes(index.Key);var length = Math.Min(128, wordData.Length);for (var i = 0; i < length; i++){word[i] = wordData[i];}idxWriter.Write(word);byte[] re = new byte[4];idxWriter.Write(index.Value.Offset);idxWriter.Write(index.Value.DataSize);}}}}
演示
如图所示
文件夹中放置了许多文本文件,内容为词语的解释
首先、建立词典:
Dict dic = new Dict("病症词典");var files = new DirectoryInfo(@"G:\Users\Administrator\Desktop\新建文件夹 (3)\新建文件夹 (3)").GetFiles();foreach (var file in files){Console.WriteLine(file.FullName);dic.Add(file.Name.Replace("的症状.txt", ""), File.ReadAllText(file.FullName));}dic.Save();
然后、把玩一番:
var dict = new Dict();while (true){Console.Write("请输入词语:");var w = Console.ReadLine();Stopwatch sw = new Stopwatch();sw.Start();Console.WriteLine("找到词语:");Console.WriteLine(dict.GetDescription(w));sw.Stop();Console.WriteLine("耗时:" + sw.ElapsedMilliseconds + "ms");}
运行结果:
到此为止,谢谢收看!
[[demo下载]]
转载于:https://www.cnblogs.com/xiaoqi/archive/2011/04/02/2003745.html
C# 词典数据结构设计【附demo】相关推荐
- 基于阿里云实现游戏数据运营(附Demo)
摘要: 原作者:阿里云解决方案架构师,陆宝.通过阅读本文,您可以学会怎样使用阿里云的maxcompute搭建一套数据分析系统. 一.总览 一个游戏/系统的业务数据分析,总体可以分为图示的几个关键步骤: ...
- Android下对Cookie的读写操作(附Demo)
转自:http://www.67tgb.com/?p=536 Cookie是为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据,在Android中也经常用到,接下来我们介绍Cooki ...
- ADO.NET Entity Framework 入门示例向导(附Demo程序下载)
ADO.NET Entity Framework 入门示例向导(附Demo程序下载) ADO.NET Entity Framework 是.Net Framework 3.5 SP1 引入的实体框架, ...
- LeetCode—211. 添加与搜索单词 - 数据结构设计
211. 添加与搜索单词 - 数据结构设计 题目描述:请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 . 实现词典类 WordDictionary : WordD ...
- 211. 添加与搜索单词 - 数据结构设计
211. 添加与搜索单词 - 数据结构设计 请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 . 实现词典类 WordDictionary : WordDictio ...
- Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码
Linux 部署ASP.NET SQLite 应用 的坎坷之旅.文章底部 附示例代码. 有一台闲置的Linux VPS,尝试着部署一下.NET 程序,结果就踏上了坑之路,不过最后算是完美解决问题,遂记 ...
- 基于opencv和pillow实现人脸识别系统(附demo)
更多python教程请到友情连接: 菜鸟教程https://www.piaodoo.com 初中毕业读什么技校 http://cntkd.net 茂名一技http://www.enechn.com p ...
- 微信小程序开发之文件上传下载应用场景(附Demo源码)
微信小程序开发之文件上传下载应用场景(附Demo源码),Demo为小相册应用,源码在附件中,本示例需要腾讯云支持. http://www.henkuai.com/forum.php?mod=viewt ...
- echarts实现3D地图,轮播功能、背景图片、鼠标悬浮展示数据,附源码!
echarts实现3D地图,轮播功能.背景图片.鼠标悬浮展示数据,附源码! 一.图片效果 二. 代码 一.图片效果 由于本地图片上传失败,无法展示完整的,不过是在此图的基础上加了轮播和底纹 二. 代码 ...
最新文章
- 利用kickstart实现pxe的自动化安装
- java e7 e9格式怎么转_java�?e7?a8??e9?a8�ӿ�
- Linux 高级流量控制
- 再探结构体字节对齐问题
- 调试网页PAIP HTML的调试与分析工具
- android 高德地图简书,Android高德之旅(4)我的位置
- H5打开APP技术总结
- MCAFEE卸载软件测试初学者,win7系统完全卸载McAfee杀毒软件的两种方法
- mysql扩容方案_MySQL分库分表:扩容方案
- 如何在电脑上录制qq语音
- 基于PLC的锅炉控制,基于s7-200的锅炉压力控制的设计,基于西门子S7-200plc与MCGS锅炉压力PID控制系统设计
- 华为交换机ARP防网关冲突
- Spring MVC 数据绑定 绑定POJO类型 filter过滤器
- 贝叶斯公式推导及意义
- CMU 15-445/645-Note11-Distributed Databases
- final修饰的变量
- 使用python输出所有汉字的拼音hàn-zì-pīn-yīn
- springboot+mysql+基于Spring boot开发电子宿舍管理系统 毕业设计-附源码132056
- Asp.net Ajax Control Toolkit设计编程备忘录(色眼窥观版)——第4回(忍者专辑)
- 安装DirectX2010报错s1023,且找不到microsoft visual c++2010 redistributable文件
热门文章
- java代码解决的问题_java代码规范问题及解决方案
- 计算机it要学什么,学习IT需要具备哪些要求?
- html5学生信息注册码,JavaScript+HTML实现学生信息管理系统代码示例
- oracle 临时文件 大文件,Oracle中临时文件File#和Db_files关系
- html5制作拼图游戏教程,用HTML5制作视频拼图的教程
- 车模型一般多少钱_婚车租赁一般多少钱?最新婚车出租价格表!
- pcb钻孔披锋改善报告_铜基板的小孔加工改善研究
- matlab重要性采样,Importance Sampling (重要性采样)介绍 | 文艺数学君
- 截取台风后的图片_Python数据分析案例 | 台风最喜欢在我国哪个省市登陆
- oracle匿名代码块执行insert,MyBatis+Oracle在执行insert时空值报错之从源码寻找解决办法...