为什么在 C#中字典比哈希表更受青睐?

在大多数编程语言中,字典比哈希表更受青睐。背后的原因是什么?

答案

对于它的价值,字典概念上一个哈希表。

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

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

通用字典是从 Hashtable 的来源复制而来的

资源

Dictionary <<<>>> Hashtable差异:

  • 通用 <<<>>> 非通用
  • 需要自己的线程同步 <<<>>> 通过Synchronized()方法提供线程安全版本
  • 枚举项: KeyValuePair <<<>>> 枚举项: DictionaryEntry
  • 较新(> .NET 2.0 )<<<>>> 较旧(自.NET 1.0 起
  • System.Collections中。 通用 <<<>>> 在System.Collections 中
  • 请求不存在的键引发异常 <<<>>> 请求不存在的键返回 null
  • 对于值类型,可能会更快 <<<>>> 对于值类型,可能会慢一点 (需要装箱 / 拆箱)

Dictionary / Hashtable相似之处:

  • 两者都是内部哈希表 == 根据密钥快速访问多项目数据
  • 两者都需要不变且唯一的键
  • 两者的键都需要自己的GetHashCode()方法

相似的 .NET 集合(代替字典和哈希表使用的候选人):

  • ConcurrentDictionary 线程安全 (可以同时从多个线程安全地访问)
  • HybridDictionary 优化的性能 (适用于少量物品,也适用于许多物品)
  • OrderedDictionary可以通过 int 索引 (按添加项目的顺序) 访问
  • SortedDictionary项目自动排序
  • StringDictionary 为字符串强类型化和优化

因为Dictionary是一个通用类( Dictionary<TKey, TValue> ),所以访问其内容是类型安全的(即,您不需要像Hashtable那样从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 中, Hashtable是线程安全的,可供多个读取器线程和一个写入线程使用,而在Dictionary公共静态成员是线程安全的,但不能保证任何实例成员都是线程安全的。

因此,我们不得不将所有的 Dictionary 重新改回Hashtable

在. NET 中, Dictionary<,>HashTable之间的区别主要在于前者是泛型类型,因此就静态类型检查(减少了装箱量)而言,您将获得泛型的所有优点,但这并不像人们倾向于从性能角度进行思考 - 但是,拳击有一定的记忆成本)。

人们说字典与哈希表相同。

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

您同样可以使用链表或搜索树来实现字典,只是效率不高(对于效率的某种度量)。

CollectionsGenerics对于处理对象组很有用。在. NET 中,所有集合对象都位于IEnumerable接口下,该接口依次具有ArrayList(Index-Value))HashTable(Key-Value) 。在. NET Framework 2.0 之后, ArrayListHashTable替换为ListDictionary 。现在, ArraylistHashTable在当今的项目中不再使用。

Hastable HashTableDictionary之间的差异, Dictionary是通用的,而Hastable不是通用的。我们可以向HashTable添加任何类型的对象,但是在检索时,我们需要将其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);
        }
    }
}

从. NET Framework 3.5 开始Dictionary<TKey, TValue>如果只需要键而不需要值,则还提供了HashSet<T> ,它提供Dictionary<TKey, TValue>所有优点。

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

字典:

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

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

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

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

    示例: Dictionary<string, string> <NameOfDictionaryVar> = new Dictionary<string, string>();

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

哈希表:

  • 如果我们尝试查找不存在的键,则返回 null。

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

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

  • 哈希表不是通用类型,

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

MSDN 上有关使用 C#进行数据结构广泛检查的文章指出, 冲突解决策略也存在差异:

Hashtable 类使用一种称为rehashing的技术。

重新哈希的工作方式如下:有一组哈希不同的函数 H 1 ... H n ,并且在从哈希表插入或检索项目时,最初使用 H 1哈希函数。如果需要的话。如果这导致了碰撞,H 2,而不是尝试,并开始长达 H n中。

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

通过重新哈希处理,在发生冲突的情况下,可以重新计算哈希,并尝试与哈希相对应的新插槽。但是,通过链接, 可以使用辅助数据结构来保存任何冲突 。具体来说,字典中的每个插槽都有一个映射到该存储桶的元素数组。在发生碰撞的情况下,碰撞元素位于铲斗列表的前面。