读书笔记——U3D高级编程:主程手记——第二章2.2List底层源码

主程手记系列

  1. 主程手记------第二章2.1读书笔记------Unity编译与GC

文章目录


C#的List数据结构的扩容原理是什么,有什么优缺点?

  1. List的底层数据结构是数组,容量不够时整个数组会扩充一倍,在声明List时不指定容量则默认容量是4
  2. 优点是索引方式提取元素很快,缺点是扩容时每次针对数组new操作会造成内存垃圾,给GC带来一些负担

C#的List数据结构的Remove移除原理是什么,时间复杂度是多少?

  1. 列表从头到尾遍历,找到首次出现的元素索引,然后用Object.Equals方法比较列表中的元素和给定值,然后用RemoveAt函数来移除指定位置的元素;所以原理就是用Array.Copy对数组覆盖
  2. 复杂度为线性迭代O(n)

C#的List数据结构的Remove移除原理是什么,时间复杂度是多少?

  1. 列表从头到尾遍历,找到首次出现的元素索引,然后用Object.Equals方法比较列表中的元素和给定值,然后用RemoveAt函数来移除指定位置的元素;所以原理就是用Array.Copy对数组覆盖
  2. 复杂度为线性迭代O(n)

C#的List数据结构的Insert插入原理是什么,时间复杂度是多少?

  1. 和Add接口一样,先检查容量是否足够,不足则扩容;并且插入元素是用复制数组的形式,将数组指定元素后面所有元素向后移动一个位置
  2. 复杂度为O(K),显然K是需要向后移动的元素数量

C#的List数据结构的Clear清除原理是什么?

  1. Clear不会删除数组,只将数组中的元素设置为0或NULL,并设置_size为0,虚拟地表明当前容量为0

C#的List数据结构的Contains原理是什么?

  1. Contains本身作用是确定某元素是否在List中,线性查找比较元素,如果查找的是null,先转化为Object来判断,如果是非null元素则通过Equals判断元素是否相等,无论查找元素是否为null,找到则返回true
csharp 复制代码
// 如果指定的元素在List中,则Contains返回true
// 它执行线性O(n)搜索。平等是通过调用item.Equals()来确定的
// 
public bool Contains(T item) {
    if ((Object) item == null) {
        for(int i=0; i<_size; i++)
            if ((Object) _items[i] == null)
                return true;
        return false;
    }
    else {
        EqualityComparer<T>c = EqualityComparer<T>.Default;
        for(int i=0; i<_size; i++) {
            if (c.Equals(_items[i], item)) return true;
        }
        return false;
    }
}

C#的List数据结构的ToArray接口原理是什么,时间复杂度多少?

  1. 通过创建指定大小的数组,然后将本身数组的内容复制到新数组上完成,但使用过多会造成大量内存分配,在内存上留下很多垃圾
  2. 显然需要遍历所有元素,所以复杂度为O(n)
csharp 复制代码
// ToArray返回一个新的Object数组,其中包含List的内容
// 这需要复制列表,这是一个O(n)操作
public T[] ToArray() {
    Contract.Ensures(Contract.Result<T[]>() != null);
    Contract.Ensures(Contract.Result<T[]>().Length == Count);

    T[] array = new T[_size];
    Array.Copy(_items, 0, array, 0, _size);
    return array;
}

C#的List数据结构的Find接口原理是什么?时间复杂度多少?

  1. 线性遍历每个元素并且比较,找到就返回
  2. 时间复杂度为O(n)
csharp 复制代码
public T Find(Predicate<T>match) {
    if( match == null) {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
    }
    Contract.EndContractBlock();

    for(int i = 0 ; i<_size; i++) {
        if(match(_items[i])) {
            return _items[i];
        }
    }
    return default(T);
}

C#的List数据结构的Enumerator接口使用有什么缺点?

  1. 每次获取迭代器时,Enumerator都会被创建出来,大量使用会产生大量垃圾对象,比如用foreach,通过foreach遍历List会增加Enumerator对象,尽管.Net4.0后已修复问题,但仍然不建议使用
csharp 复制代码
// 返回具有给定删除元素权限的此列表的枚举数
// 如果在进行枚举时对列表进行了修改,
// 则枚举器的MoveNext和GetObject方法将引发异常
// 
public Enumerator GetEnumerator() {
    return new Enumerator(this);
}

/// 仅供内部使用
IEnumerator<T>IEnumerable<T>.GetEnumerator() {
    return new Enumerator(this);
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
    return new Enumerator(this);
}

[Serializable]
public struct Enumerator : IEnumerator<T>, System.Collections.IEnumerator
{
    private List<T>list;
    private int index;
    private int version;
    private T current;

    internal Enumerator(List<T>list) {
        this.list = list;
        index = 0;
        version = list._version;
        current = default(T);
    }

    public void Dispose() {
    }

    public bool MoveNext() {

        List<T>localList = list;

        if (version == localList._version&&((uint)index<(uint)localList._size))
        {
            current = localList._items[index];
            index++;
            return true;
        }
        return MoveNextRare();
    }

    private bool MoveNextRare()
    {
        if (version != list._version) {
            ThrowHelper.ThrowInvalidOperationException(
                ExceptionResource.InvalidOperation_EnumFailedVersion);
        }

        index = list._size + 1;
        current = default(T);
        return false;
    }

    public T Current {
        get {
            return current;
        }
    }

    Object System.Collections.IEnumerator.Current {
        get {
            if( index == 0 || index == list._size + 1) {
                ThrowHelper.ThrowInvalidOperationException(
                    ExceptionResource.InvalidOperation_EnumOpCantHappen);
            }
            return Current;
        }
    }

    void System.Collections.IEnumerator.Reset() {
        if (version != list._version) {
            ThrowHelper.ThrowInvalidOperationException(
                ExceptionResource.InvalidOperation_EnumFailedVersion);
        }

        index = 0;
        current = default(T);
    }

}

C#的List数据结构的Sort接口原理是什么?

  1. 使用Array.Sort接口进行排序,而Array.Sort使用快速排序

List结构总结

  1. List本身效率不是很高,通用性强
  2. List内存分配不合理,创建List实例时需要提前声明元素容量,这样可以减少List扩容次数,进而防止List底层的数组被频繁丢弃,进而减少GC的压力
  3. List本身线程不安全,没有对多线程加锁或同步,并发情况下无法判断_size++的执行顺序,即多线程下使用List应该加安全机制

相关推荐
故事和你913 小时前
洛谷-算法2-1-前缀和、差分与离散化1
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
阿豪学编程12 小时前
面试题map/unordered相关
数据结构
武藤一雄12 小时前
19个核心算法(C#版)
数据结构·windows·算法·c#·排序算法·.net·.netcore
梦想的颜色12 小时前
mongoTemplate + Java 增删改查基础介绍
数据结构·数据库·mysql
叶小鸡14 小时前
小鸡玩算法-力扣HOT100-堆
数据结构·算法·leetcode
LUVK_15 小时前
第七章查找
数据结构·c++·考研·算法·408
khalil102016 小时前
代码随想录算法训练营Day-31贪心算法 | 56. 合并区间、738. 单调递增的数字、968. 监控二叉树
数据结构·c++·算法·leetcode·贪心算法·二叉树·递归
数智化精益手记局17 小时前
人员排班管理软件的自动化功能解析:解决传统手工人员进行排班管理耗时长的难题
运维·数据结构·人工智能·信息可视化·自动化·制造·精益工程
LeocenaY17 小时前
C语言面试题总结
c语言·开发语言·数据结构