为什么在C#中字典优于哈希表?

在大多数编程语言中,字典优于哈希表。这背后的原因是什么?

585531 次浏览

因为Dictionary是一个泛型类(Dictionary<TKey, TValue>),所以访问它的内容是类型安全的(即您不需要从Object转换,就像您对Hashtable所做的那样)。

比较

var customers = new Dictionary<string, Customer>();...Customer customer = customers["Ali G"];

var customers = new Hashtable();...Customer customer = customers["Ali G"] as Customer;

但是,Dictionary在内部实现为哈希表,因此在技术上它的工作方式相同。

在. NET中,Dictionary<,>HashTable之间的区别主要在于前者是一个泛型类型,因此您可以在静态类型检查方面获得泛型的所有好处(并减少了装箱,但这并不像人们倾向于认为的那样大)。

Hashtable是一个松散类型的数据结构,因此您可以向Hashtable添加任何类型的键和值。Dictionary类是一个类型安全的Hashtable实现,键和值是强类型的。创建Dictionary实例时,您必须同时指定键和值的数据类型。

对于它的价值,字典(概念上)是哈希表。

如果你的意思是“为什么我们使用Dictionary<TKey, TValue>类而不是Hashtable类?”,那么答案很简单:Dictionary<TKey, TValue>是泛型类型,Hashtable不是。这意味着你可以通过Dictionary<TKey, TValue>获得类型安全,因为你不能在其中插入任何随机对象,也不必强制转换你取出的值。

有趣的是,. NET Framework中的Dictionary<TKey, TValue>实现基于Hashtable,您可以从源代码中的此注释中看出:

通用字典是从Hashtable的源代码复制的

来源

仅供参考:在. NET中,Hashtable是线程安全的,可供多个读取线程和单个写入线程使用,而在Dictionary中,公共静态成员是线程安全的,但不能保证任何实例成员都是线程安全的。

因此,我们不得不将所有字典更改回Hashtable

人们说字典和哈希表是一样的。

这不一定是真的。哈希表是实施字典的一种方式。这是一个典型的方式,它可能是默认的。NET中Dictionary类中的一个,但根据定义,它不是唯一的一个。

你可以同样很好地使用链表或搜索树来实现字典,但它不会那么有效(对于一些有效的度量)。

另一个我能想到的区别是:

我们不能将字典(泛型)与Web服务一起使用。原因是没有Web服务标准支持泛型标准。

请注意,留档表示:“字典<(Of<(TKey, TValue>)>)类实现为哈希表”,而不是“字典<(Of<(TKey, TValue>)>)类实现为哈希表

字典不是作为哈希表实现的,而是按照哈希表的概念实现的。由于使用了泛型,实现与哈希表类无关,尽管在内部Microsoft可以使用相同的代码并将Object类型的符号替换为TKey和TValue。

在. NET 1.0中不存在泛型;这是HashTable和ArrayList最初开始的地方。

根据我使用. NET反射器看到的:

[Serializable, ComVisible(true)]public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable{// Fieldsprivate Hashtable hashtable;
// Methodsprotected DictionaryBase();public void Clear();...}Take note of these lines// Fieldsprivate Hashtable hashtable;

所以我们可以确定DictionaryBase在内部使用了一个哈希表。

差异

DictionaryHashtable
通用非仿制药
需要自己的线程同步提供线程安全版本到#0方法
枚举项目:#0枚举项目:#0
更新(>. net2.0旧(自. net1.0
系统。集合。通用收藏系统
请求不存在的密钥抛出异常请求不存在的密钥返回null
潜在位值类型更快值类型有点慢(需要装箱/拆箱)

相似之处:

  • 两者都是内部哈希表==根据key快速访问多项数据
  • 都需要不可变和唯一键
  • 两者的密钥都需要自己的#0方法

替代。NET集合:

(候选人使用而不是字典和哈希表)

  • ConcurrentDictionary-线程安全(可以同时从多个线程安全访问)
  • HybridDictionary-优化的性能(适用于少数项目,也适用于许多项目)
  • OrderedDictionary-值可以是通过int index访问(按项目添加的顺序)
  • SortedDictionary-项目自动排序
  • StringDictionary-强类型和针对字符串优化(现在已弃用,支持字典

Dictionary<>是泛型类型,因此它是类型安全的。

您可以在HashTable中插入任何值类型,这有时可能会引发异常。但是Dictionary<int>只接受整数值,类似地Dictionary<string>只接受字符串。

class HashTableProgram{static void Main(string[] args){Hashtable ht = new Hashtable();ht.Add(1, "One");ht.Add(2, "Two");ht.Add(3, "Three");foreach (DictionaryEntry de in ht){int Key = (int)de.Key; //Castingstring value = de.Value.ToString(); //CastingConsole.WriteLine(Key + " " + value);}
}}

class DictionaryProgram{static void Main(string[] args){Dictionary<int, string> dt = new Dictionary<int, string>();dt.Add(1, "One");dt.Add(2, "Two");dt.Add(3, "Three");foreach (KeyValuePair<int, String> kv in dt){Console.WriteLine(kv.Key + " " + kv.Value);}}}

因此,如果您使用Dictionary<MyType, object>并始终将值设置为null来模拟类型安全哈希表,您可能应该考虑切换到#2

Hashtable对象由包含集合元素的存储桶组成。存储桶是Hashtable这使得搜索和检索比大多数集合更容易和更快中元素的虚拟子组。

字典类具有与Hashtable类相同的功能。值类型的特定类型(Object除外)字典具有比Hashtable更好的性能,因为Hashtable的元素是Object类型,因此,如果存储或检索值类型,通常会发生装箱和拆箱。

更多阅读:哈希表和字典集合类型

字典:

  • 如果我们试图找到一个不存在的键,它会返回/抛出异常。

  • 它比哈希表快,因为没有装箱和拆箱。

  • 只有公共静态成员是线程安全的。

  • 字典是一种泛型类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须为键和值指定数据类型)。

    示例:Dicpedia=new字典();

  • Dictionay是Hashtable的类型安全实现,KeysValues是强类型的。

哈希表:

  • 如果我们试图找到一个不存在的键,它会返回null。

  • 它比字典慢,因为它需要装箱和拆箱。

  • 哈希表中的所有成员都是线程安全的,

  • 哈希表不是泛型类型,

  • 哈希表是松散类型的数据结构,我们可以添加任何类型的键和值。

关于MSDN的使用C#广泛检查数据结构文章指出,碰撞消解策略也有区别:

Hashtable类使用一种称为老调重弹的技术。

重新哈希的工作原理如下:有一组哈希不同的函数,H1… Hn,当从散列中插入或检索项目时表,最初使用H1哈希函数。如果这导致碰撞时,尝试H2,如果需要,则从Hn开始。

字典使用了一种称为链接的技术。

使用重新哈希,在发生冲突的情况下,重新计算哈希,并尝试与哈希对应的新槽。然而,使用链接,使用辅助数据结构来保存任何冲突。具体来说,字典中的每个槽都有一个数组映射到该存储桶的元素。如果发生碰撞,则碰撞元素被添加到存储桶列表的前面。

另一个重要的区别是Hashtable是线程安全的。Hashtable具有内置的多个读取器/单个写入器(MR/SW)线程安全,这意味着Hashtable允许一个写入器与多个读取器一起使用而无需锁定。

在字典的情况下,没有线程安全;如果您需要线程安全,您必须实现自己的同步。

进一步阐述:

哈希表通过Synchronized属性提供了一些线程安全,该属性返回一个围绕集合的线程安全包装器。包装器的工作原理是在每次添加或删除操作时锁定整个集合。因此,每个尝试访问集合的线程都必须等待轮到它来获取一个锁。这是不可扩展的,并且可能导致大型集合的性能显著下降。此外,该设计没有完全免受竞争条件的影响。

. NET Framework 2.0集合类(如List<T>, Dictionary<TKey, TValue>等)不提供任何线程同步;当在多个线程上同时添加或删除项目时,用户代码必须提供所有同步

如果您需要类型安全和线程安全,请在. NET Framework中使用并发集合类。进一步阅读这里

另一个区别是,当我们在字典中添加多个条目时,会保留添加条目的顺序。当我们从字典中检索项目时,我们将按照插入它们的相同顺序获取记录。而Hashtable不保留插入顺序。

哈希表:

键/值将在存储到堆中时转换为对象(装箱)类型。

从堆中读取时,需要将键/值转换为所需的类型。

这些操作非常昂贵。我们需要尽可能避免装箱/拆箱。

字典: HashTable的泛型变体。

没有装箱/拆箱。不需要转换。

在大多数编程语言中,字典优于哈希表

我不认为这一定是真的,大多数语言都有一个或另一个,这取决于他们喜欢的术语

然而,在C#中,(对我来说)明显的原因是C#HashTables和System. Collection命名空间的其他成员在很大程度上已经过时了。它们存在于c#V1.1中。它们已从C#2.0中被System. Colltions. Generic命名空间中的泛型类替换。