Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/280.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 列表<;T>;容量增加vs字典<;K、 V>;产能增加?_C#_.net - Fatal编程技术网

C# 列表<;T>;容量增加vs字典<;K、 V>;产能增加?

C# 列表<;T>;容量增加vs字典<;K、 V>;产能增加?,c#,.net,C#,.net,为什么列表的容量增加了2倍 private void EnsureCapacity(int min) { if (this._items.Length < min) { int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2); if (num < min) { num = min; } t

为什么
列表
的容量增加了2倍

private void EnsureCapacity(int min)
{
    if (this._items.Length < min)
    {
        int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
        if (num < min)
        {
            num = min;
        }
        this.Capacity = num;
    }
}
private void-rescapacity(int-min)
{
如果(此项长度
为什么
字典
使用素数作为容量

private void Resize()
{
    int prime = HashHelpers.GetPrime(this.count * 2);
    int[] numArray = new int[prime];
    for (int i = 0; i < numArray.Length; i++)
    {
        numArray[i] = -1;
    }
    Entry<TKey, TValue>[] destinationArray = new Entry<TKey, TValue>[prime];
    Array.Copy(this.entries, 0, destinationArray, 0, this.count);
    for (int j = 0; j < this.count; j++)
    {
        int index = destinationArray[j].hashCode % prime;
        destinationArray[j].next = numArray[index];
        numArray[index] = j;
    }
    this.buckets = numArray;
    this.entries = destinationArray;
}
private void Resize()
{
int prime=HashHelpers.GetPrime(this.count*2);
int[]numaray=新的int[prime];
for(int i=0;i

为什么不直接乘以2呢?两者都在处理查找内存位置的问题…对吗

字典根据对象的GetHashCode值将其所有对象放入bucket中,即
Bucket[object.GetHashCode()%DictionarySize]=object

它使用质数表示大小,以避免发生碰撞。假设一个有许多除数的大小对于设计糟糕的哈希代码来说是不好的。

对于哈希表大小使用素数是很常见的,因为它降低了冲突的概率

哈希表通常使用模运算来查找条目所属的bucket,如代码中所示:

int index = destinationArray[j].hashCode % prime;
假设您的hashCode函数产生以下hashCode以及其他{x,2x,3x,4x,5x,6x…},那么所有这些都将聚集在m个bucket中,其中m=table_length/GreatestCommonFactor(table_length,x)。(验证/推导这一点很简单)。现在,您可以执行以下操作之一以避免群集:

  • 请确保您不会生成太多的哈希代码,这些哈希代码是{x,2x,3x,4x,5x,6x…}中另一个哈希代码的倍数。但是如果您的哈希表应该有数百万个条目,那么这可能有点困难

  • 或者简单地通过使最大公因子(table_length,x)等于1,即通过使table_length与x互质,使m等于table_length。如果x可以是任意一个数,那么确保table_length是一个素数

  • (来自)

    应该返回一个素数。看看HashHelpers.GetPrime()的定义。

    来自SO中的a

    字典或哈希表依赖于对键进行哈希运算以获得较小的值 用于查找相应存储(数组)的索引。那么哈希的选择呢 功能非常重要。典型的选择是获取 键(以便获得良好的随机分布),然后分割代码 由一个素数,并使用提醒索引到固定数 水桶。这允许将任意大的哈希代码转换为 有界的一组小数字,我们可以为其定义一个数组来查找 一直到。所以让数组大小为素数很重要,然后 对于大小的最佳选择是变大的素数 超过所需容量。这就是字典 实现是这样的


    List
    使用
    array
    s存储数据;增加阵列的容量需要将阵列复制到新的内存位置;这很费时。我想,为了降低复制数组的发生率,list将其容量加倍。

    我不是计算机科学家,但

    最有可能的是它与a有关(最后一个链接只是一个数学定义),为了不造成更多的混乱,因为不是数学听觉,重要的是定义:

    loadFactor = FreeCells/AllCells
    
    我们可以这样写

    loadFactor = (AllBuckets - UsedBuckets)/AllBuckets
    
    loadFactor
    定义哈希映射中的冲突概率。 所以通过使用一个数字

    …是大于1的自然数 除1和自身外,没有其他正因子

    我们减少(但不消除)hashmap中的冲突风险

    如果
    loadFactor
    趋向于
    0
    ,我们有更安全的hashmap,因此我们总是必须将其保持在尽可能低的水平。通过MS,他们发现
    加载因子
    (最佳值)的值必须在
    0.72
    附近,因此,如果它变大,我们会根据最近的素数增加容量

    编辑

    更清楚地说:有一个素数,就可以确保在.NET字典中哈希的具体实现中,哈希尽可能的均匀分布。这不是关于检索值的效率,而是使用内存的效率和碰撞风险的降低


    希望这有帮助。

    字典
    需要一些启发,以便哈希代码在存储桶之间的分布更加均匀

    .NET的
    字典
    使用存储桶的素数来实现这一点,然后计算存储桶索引,如下所示:

    int num = this.comparer.GetHashCode(key) & 2147483647; // make hash code positive
    // get the remainder from division - that's our bucket index
    int num2 = this.buckets[num % ((int)this.buckets.Length)];
    
    当它增长时,它会将桶的数量增加一倍,然后再增加一些,使这个数字再次成为素数

    这不是唯一可能的启发式方法。例如,Java的
    HashMap
    采用了另一种方法。存储桶的数量始终是2的幂,在增长时,它只是存储桶数量的两倍:

    但在计算桶索引时,它会修改哈希:

    static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
    static int indexFor(int h, int length) {
        return h & (length-1);
    }
    
    // from put() method
    int hash = hash(key.hashCode()); // get modified hash
    int i = indexFor(hash, table.length); // trim the hash to the bucket count
    
    另一方面,
    List
    不需要任何启发,所以他们不需要麻烦

    添加:增长行为根本不会影响添加的复杂性<代码>字典
    哈希映射
    列表
    都摊销了O(1)的复杂性

    Grow操作需要O(N),但只发生第N次,因此要引起Grow操作,我们需要调用resize(2 * table.length);
    static int hash(int h) {
        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }
    static int indexFor(int h, int length) {
        return h & (length-1);
    }
    
    // from put() method
    int hash = hash(key.hashCode()); // get modified hash
    int i = indexFor(hash, table.length); // trim the hash to the bucket count