c# - Dictionary.Add 方法如何进行 O(1) 摊销?

标签 c# dictionary complexity-theory time-complexity

我试图从复杂性的角度更好地理解哈希表和字典在 C# 中的工作方式(但我想语言不是一个重要因素,这可能只是一个理论问题)。

我知道如果 Count 小于容量(这有点明显)。

不过,让我们看看这段代码:

public class Foo {
    public Foo() { }
    public override int  GetHashCode() {
        return 5; //arbitrary value, purposely a constant
    }
}
static void Main(string[] args) {
    Dictionary<Foo, int> test = new Dictionary<Foo,int>();
    Foo a = new Foo();
    Foo b = new Foo();

    test .Add(a, 5);
    test .Add(b, 6); //1. no exception raised, even though GetHashCode() returns the same hash

    test .Add(a, 10); //2. exception raised
}

我了解到在幕后 1. 处存在哈希冲突,并且可能有一个单独的链来处理它。

但是,在 2. 处引发了参数异常。这意味着在内部 Dictionary 会跟踪在确定其哈希后插入的每个键。这也意味着每次我们向字典添加条目时,它都会使用 equals 方法检查是否尚未插入该键。

我的问题是,如果它检查已经插入的键,为什么它看起来应该是 O(n) 的复杂度却被认为是 O(1) 的复杂度?

最佳答案

但它不必检查所有 key 。它只需要检查散列为相同值的键。而且,正如您所说,一个好的哈希码将最大限度地减少哈希冲突的次数,因此平均而言它根本不需要进行任何 key 比较。

请记住,GetHashCode 的规则说如果a.HashCode <> b.HashCode , 然后 a <> b .但是如果a.HashCode == b.GetHashCode , a 可能等于 b .

另外,你说:

Iknow that the method Add of a Dictionary is supposed to be O(1) if Count is less than the capacity (which is kind of obvious).

这不完全正确。这是理想的,假设一个完美的散列函数将为每个键提供一个唯一的数字。但在一般情况下,完美的哈希函数并不存在,因此通常您会看到 O(1)(或非常接近它)的性能,直到 Count 超过容量的某个相当大的百分比:比如 85% 或 90% .

关于c# - Dictionary.Add 方法如何进行 O(1) 摊销?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16034856/

相关文章:

c - 我们如何比较数量小于

java - 这个反向单链表算法的复杂度?

c# - 用户代码未处理常规转换 InvalidOperationException

c# - C# YamlDotNet 库是否支持合并 key ?

python - 将字符串添加到字典中的所有键(Python)

python - 无法从Python中的字典中获取值

algorithm - 这个算法的复杂度是多少?

c# - 使用 'As' 而不是 (<T>) 进行转换?

c# - 如何指定用于计算 SHA256 哈希的 key ?

dictionary - YAML:具有空值的字典