在大多数编程语言中,字典比哈希表更受欢迎。 这背后的原因是什么?
答案 0 :(得分:1497)
对于它的价值,词典 (概念上)是一个哈希表。
如果您的意思是“为什么我们使用Dictionary<TKey, TValue>
类而不是Hashtable
类?”,那么这是一个简单的答案:Dictionary<TKey, TValue>
是泛型类型,{{1} } 不是。这意味着您可以使用Hashtable
获得类型安全性,因为您无法在其中插入任何随机对象,并且您不必强制转换所取出的值。
有趣的是,.NET Framework中的Dictionary<TKey, TValue>
实现基于Dictionary<TKey, TValue>
,您可以从源代码中的注释中看出:
通用词典是从Hashtable的源代码
复制而来的
答案 1 :(得分:596)
Dictionary
&lt;&lt;&lt;&gt;&gt;&gt; Hashtable
差异:
Synchronized()
方法KeyValuePair
&lt;&lt;&lt;&gt;&gt;&gt;枚举项目: DictionaryEntry
Dictionary
/ Hashtable
相似之处:
GetHashCode()
方法类似 .NET集合(使用候选而不是Dictionary和Hashtable):
ConcurrentDictionary
- 线程安全(可以同时从多个线程安全地访问)HybridDictionary
- 优化效果(少数项目以及许多项目)OrderedDictionary
- 可以通过int index 访问值(按添加项目的顺序)SortedDictionary
- 项自动排序 StringDictionary
- 强类型和为字符串优化 答案 2 :(得分:173)
因为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
但是,{{1}}在内部实现为哈希表,因此从技术上讲它的工作方式相同。
答案 3 :(得分:84)
仅供参考:在.NET中,Hashtable
对于多个读取器线程和单个写入线程使用是线程安全的,而在Dictionary
中,公共静态成员是线程安全的,但不保证任何实例成员是线程安全的。
由于这个原因,我们不得不将所有字典更改回Hashtable
。
答案 4 :(得分:67)
在.NET中,Dictionary<,>
和HashTable
之间的区别主要在于前者是泛型类型,因此您可以在静态类型检查方面获得泛型的所有好处(并减少装箱,但这并不像人们在表现方面所认为的那么大 - 虽然拳击有一定的记忆成本。
答案 5 :(得分:32)
人们说词典与哈希表相同。
这不一定是真的。哈希表是实现字典的一种方法。这是一个典型的,它可能是Dictionary
类中.NET中的默认值,但根据定义它不是唯一的。
你同样可以使用链表或搜索树来实现字典,它只是效率不高(对某些效率指标而言)。
答案 6 :(得分:22)
Collections
&amp; Generics
对于处理对象组很有用。在.NET中,所有集合对象都在接口IEnumerable
下面,而ArrayList(Index-Value))
接口HashTable(Key-Value)
&amp; ArrayList
。在.NET framework 2.0之后,HashTable
&amp;已将List
替换为Dictionary
&amp; Arraylist
。现在,HashTable
&amp; HashTable
在现今的项目中不再使用。
Dictionary
&amp;之间的区别Dictionary
,Hastable
是通用的,因为HashTable
不是通用的。我们可以向dictionary
添加任何类型的对象,但在检索时我们需要将其强制转换为所需类型。所以,它不是类型安全的。但是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);
}
}
}
<强>词典,强>
{{1}}
答案 7 :(得分:16)
<强>词典:强>
如果我们试图找到一个不存在的密钥,它会返回/抛出异常。
它比Hashtable更快,因为没有装箱和拆箱。
只有公共静态成员是线程安全的。
Dictionary是一种泛型类型,这意味着我们可以将它与任何数据类型一起使用(创建时,必须指定键和值的数据类型)。
示例:Dictionary<string, string> <NameOfDictionaryVar> =
new Dictionary<string, string>();
Dictionay是Hashtable的类型安全实现,Keys
和Values
是强类型的。
<强>哈希表强>
如果我们尝试查找不存在的密钥,则返回null。
它比字典慢,因为它需要装箱和拆箱。
Hashtable中的所有成员都是线程安全的,
Hashtable不是通用类型,
Hashtable是松散类型的数据结构,我们可以添加任何类型的键和值。
答案 8 :(得分:15)
MSDN上的Extensive Examination of Data Structures Using C#文章指出冲突解决策略也存在差异:
Hashtable类使用称为 rehashing 的技术。
Rehashing的工作方式如下:有一组哈希不同的函数, H 1 ... H n ,以及从哈希中插入或检索项目时 表,最初使用H 1 哈希函数。如果这导致了 如果需要,尝试碰撞,H 2 ,然后再转到H n 。
字典使用称为链接的技术。
通过重新散列,在发生冲突时,重新计算散列,并尝试对应于散列的新槽。然而,通过链接,利用二级数据结构来保持 任何碰撞。具体来说,Dictionary中的每个插槽都有一个数组 映射到该存储桶的元素。在发生碰撞时, 碰撞元素被添加到存储桶列表中。
答案 9 :(得分:14)
自.NET Framework 3.5起,还有一个HashSet<T>
,如果您只需要键而没有值,则会提供Dictionary<TKey, TValue>
的所有专业人员。
因此,如果您使用Dictionary<MyType, object>
并始终将值设置为null
来模拟类型安全哈希表,则应考虑切换到HashSet<T>
。
答案 10 :(得分:12)
Hashtable
是一种松散类型的数据结构,因此您可以将任意类型的键和值添加到Hashtable
。 Dictionary
类是类型安全的Hashtable
实现,键和值是强类型的。创建Dictionary
实例时,必须为键和值指定数据类型。
答案 11 :(得分:11)
请注意,MSDN说:“Dictionary&lt;(Of&lt;(TKey,TValue&gt;)&gt;)类实现为哈希表”,而不是“Dictionary&lt;(Of&lt;(TKey) ,TValue&gt;)&gt;)类实现为 HashTable “
Dictionary不是作为HashTable实现的,而是按照哈希表的概念实现的。由于使用了泛型,实现与HashTable类无关,尽管内部Microsoft可能使用了相同的代码并用TKey和TValue替换了Object类型的符号。
在.NET 1.0中,Generics不存在;这是HashTable和ArrayList最初开始的地方。
答案 12 :(得分:8)
Hashtable对象由包含集合元素的存储桶组成。存储桶是Hashtable中虚拟的元素子组,这使得搜索和检索比大多数集合更容易,更快。
Dictionary类具有与Hashtable类相同的功能。特定类型的字典(除了Object)对于值类型具有比Hashtable 更好的性能,因为Hashtable的元素是Object类型,因此,如果存储或检索a,则通常会发生装箱和取消装箱。价值类型。
答案 13 :(得分:8)
<强>哈希表强>
键/值将在存储到堆中时转换为对象(装箱)类型。
在从堆中读取时,需要将键/值转换为所需类型。
这些操作非常昂贵。我们需要尽可能避免装箱/拆箱。
字典: HashTable的通用变体。
没有拳击/拆箱。无需转换。
答案 14 :(得分:6)
我能想出的另一个不同之处是:
我们不能使用Dictionary&lt; KT,VT&gt; (泛型)与Web服务。原因是没有Web服务标准支持泛型标准。
答案 15 :(得分:6)
Dictionary<>
是一种通用类型,所以它的类型是安全的。
您可以在HashTable中插入任何值类型,这有时会引发异常。但Dictionary<int>
只接受整数值,同样Dictionary<string>
只会接受字符串。
因此,最好使用Dictionary<>
代替HashTable
。
答案 16 :(得分:6)
另一个重要的区别是Hashtable是线程安全的。 Hashtable内置多个读取器/单个写入器(MR / SW)线程安全,这意味着Hashtable允许一个编写器与多个读取器一起使用而无需锁定。
在Dictionary的情况下,没有线程安全;如果您需要线程安全,则必须实现自己的同步。
进一步阐述:
Hashtable通过
Synchronized
属性提供一些线程安全性,该属性返回集合周围的线程安全包装器。包装器通过在每次添加或删除操作时锁定整个集合来工作。因此,尝试访问集合的每个线程必须等待轮到一个锁。这不可扩展,可能会导致大型集合的性能显着下降。此外,该设计并未完全免受竞争条件的影响。.NET Framework 2.0集合类(如
List<T>, Dictionary<TKey, TValue>
等)不提供任何线程同步;用户代码必须在多个线程上同时添加或删除项目时提供所有同步
如果您需要类型安全性以及线程安全性,请在.NET Framework中使用并发集合类。进一步阅读here。
另一个区别是,当我们在Dictionary中添加多个条目时,将保留添加条目的顺序。当我们从Dictionary中检索项目时,我们将按照插入它们的相同顺序获取记录。 Hashtable并不保留插入顺序。
答案 17 :(得分:0)
在大多数编程语言中,字典比哈希表更受欢迎
我认为这不一定是正确的,大多数语言都有一种或另一种语言,具体取决于terminology they prefer。
但是,在C#中,(对我而言)显而易见的原因是C#HashTables和System.Collections命名空间的其他成员已经过时了。它们存在于c#V1.1中。它们已从C#2.0中被System.Collections.Generic命名空间中的Generic类替换。
答案 18 :(得分:-3)
根据我使用.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。