分析

要建立词典,最基本的应该有词典的描述信息、词典索引文件以及词典数据文件。

/// <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;}}

数据结构说明:

  1. 描述信息包含词典名字,词典词语数量
  2. 索引文件存储的是排好顺序词语的索引,每个索引包含词语名称、存在数据文件中的偏移量、以及数据块大小,排序的目的在于查找时直接用二分查找节省查找时间。
  3. 数据块就简单了,就纯粹的数据

建立词典

建立词典比较简单,首先,定义几个变量来存储词典相关信息:

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】相关推荐

  1. 基于阿里云实现游戏数据运营(附Demo)

    摘要: 原作者:阿里云解决方案架构师,陆宝.通过阅读本文,您可以学会怎样使用阿里云的maxcompute搭建一套数据分析系统. 一.总览 一个游戏/系统的业务数据分析,总体可以分为图示的几个关键步骤: ...

  2. Android下对Cookie的读写操作(附Demo)

    转自:http://www.67tgb.com/?p=536 Cookie是为了辨别用户身份.进行session跟踪而储存在用户本地终端上的数据,在Android中也经常用到,接下来我们介绍Cooki ...

  3. ADO.NET Entity Framework 入门示例向导(附Demo程序下载)

    ADO.NET Entity Framework 入门示例向导(附Demo程序下载) ADO.NET Entity Framework 是.Net Framework 3.5 SP1 引入的实体框架, ...

  4. LeetCode—211. 添加与搜索单词 - 数据结构设计

    211. 添加与搜索单词 - 数据结构设计 题目描述:请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 . 实现词典类 WordDictionary : WordD ...

  5. 211. 添加与搜索单词 - 数据结构设计

    211. 添加与搜索单词 - 数据结构设计 请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 . 实现词典类 WordDictionary : WordDictio ...

  6. Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码

    Linux 部署ASP.NET SQLite 应用 的坎坷之旅.文章底部 附示例代码. 有一台闲置的Linux VPS,尝试着部署一下.NET 程序,结果就踏上了坑之路,不过最后算是完美解决问题,遂记 ...

  7. 基于opencv和pillow实现人脸识别系统(附demo)

    更多python教程请到友情连接: 菜鸟教程https://www.piaodoo.com 初中毕业读什么技校 http://cntkd.net 茂名一技http://www.enechn.com p ...

  8. 微信小程序开发之文件上传下载应用场景(附Demo源码)

    微信小程序开发之文件上传下载应用场景(附Demo源码),Demo为小相册应用,源码在附件中,本示例需要腾讯云支持. http://www.henkuai.com/forum.php?mod=viewt ...

  9. echarts实现3D地图,轮播功能、背景图片、鼠标悬浮展示数据,附源码!

    echarts实现3D地图,轮播功能.背景图片.鼠标悬浮展示数据,附源码! 一.图片效果 二. 代码 一.图片效果 由于本地图片上传失败,无法展示完整的,不过是在此图的基础上加了轮播和底纹 二. 代码 ...

最新文章

  1. 利用kickstart实现pxe的自动化安装
  2. java e7 e9格式怎么转_java�?e7?a8??e9?a8�ӿ�
  3. Linux 高级流量控制
  4. 再探结构体字节对齐问题
  5. 调试网页PAIP HTML的调试与分析工具
  6. android 高德地图简书,Android高德之旅(4)我的位置
  7. H5打开APP技术总结
  8. MCAFEE卸载软件测试初学者,win7系统完全卸载McAfee杀毒软件的两种方法
  9. mysql扩容方案_MySQL分库分表:扩容方案
  10. 如何在电脑上录制qq语音
  11. 基于PLC的锅炉控制,基于s7-200的锅炉压力控制的设计,基于西门子S7-200plc与MCGS锅炉压力PID控制系统设计
  12. 华为交换机ARP防网关冲突
  13. Spring MVC 数据绑定 绑定POJO类型 filter过滤器
  14. 贝叶斯公式推导及意义
  15. CMU 15-445/645-Note11-Distributed Databases
  16. final修饰的变量
  17. 使用python输出所有汉字的拼音hàn-zì-pīn-yīn
  18. springboot+mysql+基于Spring boot开发电子宿舍管理系统 毕业设计-附源码132056
  19. Asp.net Ajax Control Toolkit设计编程备忘录(色眼窥观版)——第4回(忍者专辑)
  20. 安装DirectX2010报错s1023,且找不到microsoft visual c++2010 redistributable文件

热门文章

  1. java代码解决的问题_java代码规范问题及解决方案
  2. 计算机it要学什么,学习IT需要具备哪些要求?
  3. html5学生信息注册码,JavaScript+HTML实现学生信息管理系统代码示例
  4. oracle 临时文件 大文件,Oracle中临时文件File#和Db_files关系
  5. html5制作拼图游戏教程,用HTML5制作视频拼图的教程
  6. 车模型一般多少钱_婚车租赁一般多少钱?最新婚车出租价格表!
  7. pcb钻孔披锋改善报告_铜基板的小孔加工改善研究
  8. matlab重要性采样,Importance Sampling (重要性采样)介绍 | 文艺数学君
  9. 截取台风后的图片_Python数据分析案例 | 台风最喜欢在我国哪个省市登陆
  10. oracle匿名代码块执行insert,MyBatis+Oracle在执行insert时空值报错之从源码寻找解决办法...