List是c#中的一个最常见的可伸缩数组组件,不用手动去分配数组大小
初始容量是0
优点:使用索引方式提取数组很快,通用性高
缺点:扩容时会很糟糕,每次针对数组进行new操作都会造成内存垃圾,给gc带来巨大负担。效率不高
常用接口分析
(1)Add接口
给定对象添加到列表的末尾,列表的大小+1
容量不够,将会增加到当前容量的两倍
4,8,16,32,64,128
溢出(大约2gb)之前,会允许列表增长到最大容量
(2)Remove接口
删除给定索引处的元素,列表大小减1
返回此列表范围内给定值首次出现的索引,该列表从头向尾向前搜索
用Array.IndexOf执行搜索
使用Object.Equals方法将列表中的元素与给定值进行比较
删除原理是使用Array.Copy对数组进行覆盖
O(n)
(3)Insert接口
给定索引处将元素插入此列表,列表大小增加1
如果需要,在插入新元素之前,列表的容量会增加一倍
使用Array.Copy进行复制数组,将数组里指定元素后面的所有元素向后移动一个位置
(4)[]接口(public T this[int index])
这里是直接使用数组的索引方式获取元素
(5)Clear接口
调用时并不会删除数组,而只是将数组中的元素设置为0或者null,而且size也设置成0.
(6)Contains接口,Find接口
用线性查找方式比较元素,对数组执行循环操作
(7)ToArray接口(public T[] ToArray())
重新创造了一个指定大小的数组,将本身数组上的内容复制到新数组再返回,如果使用过多,会造成大量内存的分配,在内存留下很多无用的垃圾。
(8)Enumerator接口
这里也就是循环遍历的意思
每次获取迭代器时,Enumerator都会被创造出来,如果大量使用迭代器,比如foeach,就会产生大量的垃圾,所以尽量不要使用foreach,因为List的foreach会增加Enumerator实例,最后被GC,虽然后面net4.0修复了这个问题,但还是不建议大量使用。而且foreach不能边遍历边修改。
(9)Sort接口
内部使用快排进行排序,O(nlogn)
总结
好用但是效率不高
1.List里的接口都是没有做过任何形式的优化的,使用的都是顺序迭代的方式,过于频繁的使用,效率会降低,也会造成内存冗余,使得GC要承担更多压力
2.List只是通用性高,大部分算法都是使用的是线性复杂度的算法,当遇到规模较大的计算量级时,这种线性算法会导致cpu的内存大量消耗。
3.List内存分配不合理,元素不断增加会多次重新分配数组,导致原来的被遗弃,gc会造成回收压力
4.线程不安全,并没有对多线程做任何加锁或者其他同步操作
改进
1.自己写一套
2.创建List实例的时候告诉List最多会有多少元素在里面
3.多线程使用期间应加上安全机制