设为首页 加入收藏

TOP

C#基础复习(4) 之 浅析List、Dictionary(五)
2019-09-17 18:58:29 】 浏览:131
Tags:基础 复习 浅析 List Dictionary
何时扩容

Dictionary内部实际上是维护了两个数组对数据进行保存,既然是数组,那么自然会有数组放满的风险,根据前面的Add方法源码的分析,可以看到其中有一行当count(空闲位置)== hash桶长度时,会进行扩容操作。

这是扩容比较直观的触发条件。在另外一种情况下Dictionary也会触发扩容,这就是当碰撞次数过多时,它会自动扩容。

那么什么是碰撞呢?

在FindEntry方法中,当我们沿着同类冲突元素的单链表一直找下去的时候,每遍历一个元素,碰撞次数collisionCount就+1,当碰撞次数超过设定好的阈值时,就会触发扩容。

FindEntry方法源码中触发碰撞的代码:

private int FindEntry(TKey key)
{
    ....
    // 碰撞次数
    int collisionCount = 0;
    ...
    do
    {
        if ((uint)i >= (uint)entries.Length || (entries[i].hashCode == hashCode && EqualityComparer<TKey>.Default.Equals(entries[i].key, key)))
        {
            break;
        }

        i = entries[i].next;
        if (collisionCount >= entries.Length)
        {
            ThrowHelper.ThrowInvalidOperationException_ConcurrentOperationsNotSupported();
        }
        // 在遍历这个单链表的时候,每查找失败一次,碰撞次数+1
        collisionCount++;
    } while (true);
    ...
}

很显然这个碰撞次数就关系到了我们前面说的查找方法的消耗时间,所以当碰撞次数超过阈值,Dictionary就自动扩容了,并且在扩容后还会使用新的Hash函数来进行HashCode值。

version(版本)和迭代的关系

在C#中,增、删、改操作都会使得Dictionary中的version(版本)变量改变。

这里依旧引用一下@InCerry大大的博文对于这个的解释。

迭代过程中不允许集合出现变化。如果在Java中遍历直接删除元素,会出现诡异的问题,所以.Net中就使用了version来实现版本控制。

那么如何在迭代过程中实现版本控制的呢?我们看一看源码就很清楚的知道。

在迭代器初始化时,就会记录dictionary.version版本号,之后每一次迭代过程都会检查版本号是否一致,如果不一致将抛出异常。

Dictionary的增删查改效率如何?

经过上面的分析,我们就可以知道Dictionary的增删改查效率了,列表如下:

数据结构 Add Remove Find Alter
Dictionary O(1) O(1) O(1) O(1)

可以看到字典这个数据结构还是相当给力的,基本的操作流程基本都是O(1)的复杂度,不过它会消耗更多的空间就是了(毕竟使用了两个数组进行维护)。

总结

这篇博文也是写的相当久,因为我基础不是很牢固,一开始写这个系列的就是为了巩固下C#基础,所以可能出现了一些错误,如果有读者看到,还请不吝指出,我会非常感激的。(话说上一篇String和StringBuilder的错误还没改。。懒癌发作。。)

本篇文章后半段关于Dictionary的部分大部分是参考@InCerry的博文【浅析C# Dictionary实现原理】(讲的相当清楚)所写的,emmmm,如果有什么版权方面的问题,请联系我,我会立即删除这篇文章。

首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇接之前的文章,VS2017中使用Sprin.. 下一篇C#相等性 - 三个方法和一个接口

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目