在大多数编程语言中,字典比哈希表更受欢迎。这背后的原因是什么?
Dictionary
是 Hashtable
的实现。
HashTable
不同,是通用的。
对于它的价值,字典是(概念上)一个哈希表。
如果您的意思是“为什么我们使用 Dictionary<TKey, TValue>
类而不是 Hashtable
类?”,那么答案很简单:Dictionary<TKey, TValue>
是泛型类型,Hashtable
不是。这意味着您可以使用 Dictionary<TKey, TValue>
获得类型安全,因为您不能将任何随机对象插入其中,并且您不必强制转换取出的值。
有趣的是,.NET Framework 中的 Dictionary<TKey, TValue>
实现基于 Hashtable
,您可以从其源代码中的注释中看出:
通用字典是从 Hashtable 的源代码中复制的
差异
Dictionary Hashtable Generic Non-Generic 需要自己的线程同步 通过 Synchronized() 方法提供线程安全版本 Enumerated item: KeyValuePair Enumerated item: DictionaryEntry Newer (> .NET 2.0) Older (since .NET 1.0) is in System.Collections.Generic is in System.Collections 对不存在的键的请求引发异常 对不存在的键的请求返回 null 对于值类型可能快一点 对于值类型慢一点(需要装箱/拆箱)
相似之处:
两者都是内部哈希表 == 根据键快速访问多项数据
两者都需要不可变和唯一的键
两者的键都需要自己的 GetHashCode() 方法
替代 .NET 集合:
(可以代替 Dictionary 和 Hashtable 使用的候选人)
ConcurrentDictionary - 线程安全(可以同时从多个线程安全访问)
HybridDictionary - 优化的性能(对于少数项目和许多项目)
OrderedDictionary - 可以通过 int index 访问值(按添加项目的顺序)
SortedDictionary - 自动排序的项目
StringDictionary - 为字符串强类型化和优化(现在不推荐使用 Dictionary
StringDictionary
...btw StringDictionary
+1 与 Dictionary<string, string>
不同。
因为 Dictionary
是一个通用类 ( Dictionary<TKey, TValue>
),所以访问它的内容是类型安全的(即您不需要像 Hashtable
那样从 Object
进行转换)。
相比
var customers = new Dictionary<string, Customer>();
...
Customer customer = customers["Ali G"];
至
var customers = new Hashtable();
...
Customer customer = customers["Ali G"] as Customer;
但是,Dictionary
在内部实现为哈希表,因此从技术上讲,它的工作方式相同。
仅供参考:在 .NET 中,Hashtable
是线程安全的,可供多个读取线程和单个写入线程使用,而在 Dictionary
中,公共静态成员是线程安全的,但不保证任何实例成员都是线程安全的。
因此,我们不得不将所有字典改回 Hashtable
。
ConcurrentDictionary
类,该类将所有公共/受保护的方法实现为线程安全的。如果您不需要支持旧平台,这可以让您替换多线程代码中的 Hashtable
:msdn.microsoft.com/en-us/library/dd287191.aspx
在 .NET 中,Dictionary<,>
和 HashTable
之间的区别主要在于前者是泛型类型,因此您可以在静态类型检查方面获得泛型的所有好处(并减少装箱,但这并没有那么大正如人们倾向于从性能方面考虑的那样——尽管拳击有一定的内存成本)。
人们说字典与哈希表相同。
这不一定是真的。哈希表是实现字典的一种方式。一个典型的,它可能是 .NET 中 Dictionary
类中的默认一个,但根据定义,它不是唯一的一个。
您同样可以使用链表或搜索树来实现字典,只是效率不高(对于某些效率指标)。
Dictionary<K,V>
时应该保证您是哈希表。 IDictionary<K,V>
可以是任何东西,但 :)
Collections
& Generics
对于处理对象组很有用。在 .NET 中,所有集合对象都位于接口 IEnumerable
下,而该接口又具有 ArrayList(Index-Value))
& HashTable(Key-Value)
。 .NET 框架 2.0 之后,ArrayList
& HashTable
被替换为 List
& Dictionary
。现在,Arraylist
& HashTable
在当今的项目中不再使用。
HashTable
& 之间的区别Dictionary
,Dictionary
是通用的,而 Hastable
不是通用的。我们可以将任何类型的对象添加到 HashTable
,但在检索时我们需要将其转换为所需的类型。所以,它不是类型安全的。但是对于dictionary
,我们可以在声明自己的同时指定key和value的类型,所以不需要在检索的时候进行强制转换。
让我们看一个例子:
哈希表
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; //Casting
string value = de.Value.ToString(); //Casting
Console.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);
}
}
}
字典:
如果我们试图找到一个不存在的键,它会返回/抛出异常。
它比 Hashtable 更快,因为没有装箱和拆箱。
只有公共静态成员是线程安全的。
Dictionary 是一种通用类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须为键和值指定数据类型)。示例: Dictionary
Dictionay 是 Hashtable 的类型安全实现,键和值是强类型的。
哈希表:
如果我们试图找到一个不存在的键,它会返回 null。
它比字典慢,因为它需要装箱和拆箱。
Hashtable 中的所有成员都是线程安全的,
Hashtable 不是泛型类型,
Hashtable 是松散类型的数据结构,我们可以添加任何类型的键和值。
Dictionary.TryGetValue
,则不会
MSDN 上的 Extensive Examination of Data Structures Using C# 文章指出,冲突解决策略也存在差异:
Hashtable 类使用一种称为重新散列的技术。
重新散列的工作原理如下:有一组散列不同的函数,H1 ... Hn,当从散列表中插入或检索项目时,最初使用 H1 散列函数。如果这导致了冲突,则尝试使用 H2,如果需要,可以继续尝试 Hn。
Dictionary 使用一种称为链接的技术。
通过重新散列,在发生冲突时重新计算散列,并尝试与散列对应的新槽。然而,通过链接,使用辅助数据结构来保存任何冲突。具体来说,字典中的每个插槽都有一个映射到该存储桶的元素数组。如果发生碰撞,碰撞元素将被添加到存储桶列表中。
从 .NET Framework 3.5 开始,如果您只需要键而不需要值,还有一个 HashSet<T>
可以提供 Dictionary<TKey, TValue>
的所有优点。
因此,如果您使用 Dictionary<MyType, object>
并始终将值设置为 null
来模拟类型安全哈希表,您可能应该考虑切换到 HashSet<T>
。
Hashtable
是一种松散类型的数据结构,因此您可以将任何类型的键和值添加到 Hashtable
。 Dictionary
类是类型安全的 Hashtable
实现,键和值是强类型的。创建 Dictionary
实例时,您必须指定键和值的数据类型。
请注意,the documentation 说:“Dictionary<(Of <(TKey, TValue>)>) 类实现为 哈希表”,而不是“Dictionary<(Of <( TKey, TValue>)>) 类实现为 HashTable"
字典不是作为哈希表实现的,而是按照哈希表的概念来实现的。由于使用了泛型,该实现与 HashTable 类无关,尽管 Microsoft 在内部可以使用相同的代码并将 Object 类型的符号替换为 TKey 和 TValue。
在 .NET 1.0 中不存在泛型;这是 HashTable 和 ArrayList 最初开始的地方。
哈希表:
键/值将在存储到堆中时转换为对象(装箱)类型。
从堆中读取时,需要将键/值转换为所需的类型。
这些操作非常昂贵。我们需要尽可能避免装箱/拆箱。
Dictionary : HashTable 的通用变体。
没有装箱/拆箱。无需转换。
Hashtable 对象由包含集合元素的存储桶组成。存储桶是 Hashtable 中元素的虚拟子组,它使搜索和检索比大多数集合更容易和更快。
Dictionary 类与 Hashtable 类具有相同的功能。对于值类型,特定类型(Object 除外)的 Dictionary 比 Hashtable 具有更好的性能,因为 Hashtable 的元素属于 Object 类型,因此,在存储或检索值类型时通常会发生装箱和拆箱。
进一步阅读:Hashtable and Dictionary Collection Types
另一个重要的区别是 Hashtable 是线程安全的。 Hashtable 具有内置的多读取器/单写入器 (MR/SW) 线程安全性,这意味着 Hashtable 允许一个写入器与多个读取器一起使用而无需锁定。
在 Dictionary 的情况下,没有线程安全;如果您需要线程安全,则必须实现自己的同步。
进一步阐述:
Hashtable 通过 Synchronized 属性提供一些线程安全性,该属性返回集合周围的线程安全包装器。包装器通过在每次添加或删除操作时锁定整个集合来工作。因此,每个试图访问集合的线程都必须等待轮到它来获取一个锁。这是不可扩展的,并且可能导致大型集合的性能显着下降。此外,该设计并未完全免受竞争条件的影响。 List
如果您需要类型安全以及线程安全,请使用 .NET Framework 中的并发集合类。进一步阅读here。
另一个区别是,当我们在 Dictionary 中添加多个条目时,会保持添加条目的顺序。当我们从 Dictionary 中检索项目时,我们将以插入它们的相同顺序获取记录。而 Hashtable 不保留插入顺序。
Hashset
在不涉及删除的使用场景中保证 MR/SW 线程安全。我认为这可能是为了完全保证 MR/SW 安全,但是安全地处理删除大大增加了 MR/SW 安全的费用。虽然 Dictionary
的设计可以在不可删除场景中以最低成本提供 MR/SW 安全性,但我认为 MS 希望避免将不可删除场景视为“特殊”。
我能弄清楚的另一个区别是:
我们不能在 Web 服务中使用 Dictionary
Dictionary<>
是泛型类型,因此它是类型安全的。
您可以在 HashTable 中插入任何值类型,这有时可能会引发异常。但 Dictionary<int>
只接受整数值,同样 Dictionary<string>
只接受字符串。
因此,最好使用 Dictionary<>
而不是 HashTable
。
在大多数编程语言中,字典比哈希表更受欢迎
我认为这不一定是正确的,大多数语言都有其中一种,具体取决于 terminology they prefer。
然而,在 C# 中,(对我而言)明显的原因是 C# HashTables 和 System.Collections 命名空间的其他成员在很大程度上已经过时。它们出现在 c# V1.1 中。从 C# 2.0 开始,它们已被 System.Collections.Generic 命名空间中的通用类取代。
根据我使用 .NET Reflector 看到的:
[Serializable, ComVisible(true)]
public abstract class DictionaryBase : IDictionary, ICollection, IEnumerable
{
// Fields
private Hashtable hashtable;
// Methods
protected DictionaryBase();
public void Clear();
.
.
.
}
Take note of these lines
// Fields
private Hashtable hashtable;
所以我们可以确定 DictionaryBase 在内部使用了一个 HashTable。
不定期副业成功案例分享
HashTable
(类)和Dictionary
(类)都是哈希表(概念),但HashTable
不是Dictionary
,Dictionary
也不是HashTable
。它们以非常相似的方式使用,并且Dictionary<Object,Object>
可以以与HashTable
相同的无类型方式运行,但它们不直接共享任何代码(尽管部分可能以非常相似的方式实现)。