C#框架提供的几种数据结构对单值查找的效率比较
做分词组件时,有网友提出采用Hashtable 数据结构查找字符串效率较低,建议改为Dictionary,其理由是采用Hashtable 时Key值是object 会触发装箱和拆箱动作,一直对这种说法表示怀疑,因为我理解只有值类型和引用类型通过object 互转时才会发生装箱和查询,引用类型之间强制转换不应发生装箱和拆箱,而Dictionary 泛型实际上底层还是调用的Hashtable,所以效率怎么会比Hashtable 要高呢?今天决定对比较常用的4种数据结构做一个测试,以便以后做系统性能优化时做一个参考。
这四种数据结构分别是 Hashtable, Dictionary, SortedDictionary,SortedList。它们所代表的数据结构分别是 哈希表、哈希表、二叉索引树和二分查找。测试设计如下。以10万条数据为一组,按照每条记录的字符串长度不同分为3组,分别是16,128,1024,并且分别根据原数据是排序的还是不排序的两种情况进行插入和单值查找的测试。测试时间单位为毫秒。下面看测试结果
插入的测试结果 (所有结果都是插入10万次的总时间)
测试条件 | HashTable | Dictionary | SortedDictionary | SortedList |
字符串长度 16,未排序 | 14 | 21 | 896 | 8009 |
字符串长度 16,已排序 | 25 | 35 | 990 | 671 |
字符串长度 128,未排序 | 30 | 52 | 868 | 8415 |
字符串长度 128,已排序 | 43 | 67 | 1053 | 666 |
字符串长度 1024,未排序 | 132 | 262 | 1269 | 8159 |
字符串长度 1024,已排序 | 158 | 277 | 1036 | 684 |
查询的测试结果 (所有结果都是查询10万次的总时间)
测试条件 | HashTable | Dictionary | SortedDictionary | SortedList |
字符串长度 16,未排序 | 13 | 15 | 412 | 366 |
字符串长度 16,已排序 | 25 | 29 | 349 | 315 |
字符串长度 128,未排序 | 31 | 40 | 492 | 438 |
字符串长度 128,已排序 | 42 | 54 | 408 | 371 |
字符串长度 1024,未排序 | 130 | 202 | 934 | 894 |
字符串长度 1024,已排序 | 160 | 219 | 801 | 757 |
从测试结果上看,无论是插入和查询,Hashtable的效率是最高的 其次是Dictionary 这和我的预期基本是一致的。
采用哈希方式插入,时间主要消耗在对哈希冲突情况的处理上,但由于只是选择空闲的桶而没有另外进行内存分配,其消耗时间是有限的。这里需要说明的是在我的测试设计中已经将每种数据结构的初始值设置为10万。而Dictionary 由于在Hashtable基础上封装了一层,效率稍有下降。
采用二叉搜索树插入,时间消耗在对树的节点的维护以及查找上(因为每次插入前需要确定记录是否有重复,重复记录不插入)。
二分查找,由于底层是一个顺序数组,当顺序插入时,效率比二叉搜索树稍高,当随机插入时会要求不断调整元素在数组中的位置,这导致大量的大块内存的拷贝,所以这种情况下效率极低,而且随着元素个数的增加会成指数上升。
哈希查找的时间消耗主要还是在冲突情况的匹配上,哈希函数的计算一般是很快的。但这里有一点必须要注意到,就是.net string 类型的特殊性,由于相同的string 指向相同的地址,所以在string 进行两两比较时,只比较地址,而不是每个字符都去计算,这大大提高了比较的效率。
而其他两种方式则需要比较字符串的大小,而不是仅仅比较相等,这带来了非常大的开销。
结论
对以字符串为主键的单值查找的优先选择 Hashtable 或者 Dictionary. 个人觉得如果只注重效率的话, Hashtable 更好一些,特别是在字符串较长时其效率几乎比Dictionary 快将近一倍。
测试代码
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace StringDictionaryPerformance
{
class Program
{
static Random _Rand = new Random();
static Hashtable _Hashtable;
static Dictionary<string, int> _Dictionary;
static SortedDictionary<string, int> _SortDictionary ;
static SortedList<string, int> _SortedList ;
static string GetRandString(int length)
{
StringBuilder str = new StringBuilder();
for (int i = 0; i < length; i++)
{
str.Append((char)_Rand.Next(32, 128));
}
return str.ToString();
}
static List<string> GetTestStrings(int length, int number)
{
List<string> retVal = new List<string>(number);
for (int i = 0; i < number; i++)
{
retVal.Add(GetRandString(length));
}
return retVal;
}
static void TestInsert(List<string> strings, bool sort)
{
if (sort)
{
strings.Sort();
}
Console.WriteLine(string.Format("TestInsert string length = {0} count of strings = {1} sort={2}",
strings[0].Length, strings.Count, sort));
Stopwatch stopWatch = new Stopwatch();
Console.WriteLine("Begin Hashtable");
_Hashtable = new Hashtable(strings.Count);
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (_Hashtable[strings[i]] != null)
{
_Hashtable.Add(strings[i], i);
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin Dictoinary");
_Dictionary = new Dictionary<string,int>(strings.Count);
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_Dictionary.ContainsKey(strings[i]))
{
_Dictionary.Add(strings[i], i);
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin SortDictionary");
_SortDictionary = new SortedDictionary<string, int>();
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_SortDictionary.ContainsKey(strings[i]))
{
_SortDictionary.Add(strings[i], i);
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin SortedList");
_SortedList = new SortedList<string, int>(strings.Count);
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_SortedList.ContainsKey(strings[i]))
{
_SortedList.Add(strings[i], i);
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
}
static void TestFind(List<string> strings, bool sort)
{
Console.WriteLine(string.Format("TestFind string length = {0} count of strings = {1} sort={2}",
strings[0].Length, strings.Count, sort));
Stopwatch stopWatch = new Stopwatch();
Console.WriteLine("Begin Hashtable");
_Hashtable = new Hashtable(strings.Count);
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (_Hashtable[strings[i]] != null)
{
Console.WriteLine("Error!");
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin Dictoinary");
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_Dictionary.ContainsKey(strings[i]))
{
Console.WriteLine("Error!");
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin SortDictionary");
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_SortDictionary.ContainsKey(strings[i]))
{
Console.WriteLine("Error!");
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
Console.WriteLine("Begin SortedList");
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < strings.Count; i++)
{
if (!_SortedList.ContainsKey(strings[i]))
{
Console.WriteLine("Error!");
}
}
stopWatch.Stop();
Console.WriteLine(string.Format("ElapsedMilliseconds = {0} ms", stopWatch.ElapsedMilliseconds));
}
static void Main(string[] args)
{
List<string> strings;
strings = GetTestStrings(16, 100000);
TestInsert(strings, false);
TestFind(strings, false);
TestInsert(strings, true);
TestFind(strings, true);
strings = GetTestStrings(128, 100000);
TestInsert(strings, false);
TestFind(strings, false);
TestInsert(strings, true);
TestFind(strings, true);
strings = GetTestStrings(1024, 100000);
TestInsert(strings, false);
TestFind(strings, false);
TestInsert(strings, true);
TestFind(strings, true);
}
}
}
转载于:https://www.cnblogs.com/zcy_soft/archive/2010/10/02/1841167.html
C#框架提供的几种数据结构对单值查找的效率比较相关推荐
- 图解Redis中的9种数据结构(高级面试,必备)
如图所示,Redis中提供了9种不同的数据操作类型,他们分别代表了不同的数据存储结构. 图2-17 数据类型 String类型 String类型是Redis用的较多的一个基本类型,也是最简单的一种类型 ...
- android自定义dialog开源库,android-dialog: 此框架提供五种对话框的显示,并支持对话框的扩展,目的是为了提供对话框的统一管理,并提供对话框显示的公共接口。...
android-dialog 此框架提供七种对话框的显示,并支持对话框的扩展,目的是为了提供对话框的统一管理,并提供对话框显示的公共接口. LoadingDialog:正在加载对话框 MessageD ...
- 每个程序员都应该学习的 6 种数据结构
数据结构和算法是编程的支柱,这里有6个Java程序员应该学习的基本数据结构 扫码关注<Java学研大本营>,加入读者群,分享更多精彩 数据结构是程序的构建块.甚至有人说"数据结构 ...
- 年后跳槽BAT必看:10种数据结构、算法和编程课助你面试通关
作者 | javinpaul 译者 | 大鱼 编辑 | 一一 出品 | AI 科技大本营 进入 BAT 这样的巨头企业工作,无疑是很多程序员的梦想.但事实上,能通过这些公司高难度编程面试的只是一小撮人 ...
- 每个程序员都必须知道的 8 种数据结构
点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 快速介绍8种数据结构 数据结构是一种特殊的组织和存储数据的方式,可 ...
- 万字长文的Redis五种数据结构详解(理论+实战),建议收藏。
本文脑图 前言 Redis是基于c语言编写的开源非关系型内存数据库,可以用作数据库.缓存.消息中间件,这么优秀的东西一定要一点一点的吃透它. 关于Redis的文章之前也写过三篇,阅读量和读者的反映都还 ...
- 每个程序员都必须知道的8种数据结构
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | http://suo.im/6oo92L 快速 ...
- Redis五种数据结构详解
Redis是基于c语言编写的开源非关系型内存数据库,可以用作数据库.缓存.消息中间件,这么优秀的东西一定要一点一点的吃透它. Redis的五种数据结构包括以下五种: String:字符串类型 List ...
- SpringCloud(第 025 篇)Zuul 路由后面的微服务挂了后,Zuul 提供了一种回退机制来应对熔断处理...
2019独角兽企业重金招聘Python工程师标准>>> SpringCloud(第 025 篇)Zuul 路由后面的微服务挂了后,Zuul 提供了一种回退机制来应对熔断处理 一.大致 ...
最新文章
- 静态属性和静态方法2 - C++快速入门22
- 嘿 Siri,有没有「三天速成深度学习」的课程?
- 太形象!打工人入职前后的心理变化 | 每日趣闻
- php读取 rss pubdate,PHP产生RSS pubDate所需日期时间格式的方法
- linux alpine 提示'/bin/sh: rc-service: not found'解决方案
- linux 视频相关资源
- 改变外观_“改”出来的精彩!盘点5种改变葫芦外观的技艺
- php遇到Allowed memory size of 134217728 bytes exhausted问题解决方法
- 微信小程序API之request
- Facebook开源新的压缩算法,性能超zlib
- Ubuntu server解决不能访问外网问题
- windows服务创建工具srvany.exe介绍
- 有些东西还得记下来,看过了又忘了,找起来又难找 (fluxbox, ab, seige)
- 一招教你如何改变图片的大小?只需三步简单实用
- 从一个帝国的消逝,看商业组织的进化
- 江西赣州计算机应用中心,赣州计算机应用与维修专业学校
- 【网络工程】计算机网络专业术语概论全面整理
- Deep Learning on Graphs: A Survey论文笔记
- 腾讯云服务器--学生优惠版购买以及配置方法
- antd form 表单数据校验·记
热门文章
- 【转】使用 F#、MapReduce 和 Windows Azure 分析日志文件
- NET在后置代码中输入JS提示语句(背景不会变白)
- java 蓝桥杯算法训练 求1加到x的和(number)
- schedule php,PHP Laravel定时任务Schedule【干货】
- (68)FPGA面试题-使用不同的代码实现2:1 MUX ?使用assign语句
- (41)System Verilog输出变量时序延迟
- (05)FPGA内部资源
- (31)FPGA面试题系统最高速度计算方法
- FPGA常用单位换算
- 函数平移口诀_初三二次函数平移规律的口诀