1. List

// C# 源码

public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>

{

private const int _defaultCapacity = 4;//默认容量为4

private T[] _items;//list内部是用数组实现的

[ContractPublicPropertyName("Count")]

private int _size;

private int _version;//在遍历时如果发现_version变了立即退出并抛出遍历过程集合被修改异常,比如在foreach里remove或add元素就会导致这个异常。更常见的是出现在多线程时一个线程遍历集合,另一个线程修改集合的时候,相信很多人吃过苦头。

[NonSerialized]

private Object _syncRoot;

static readonly T[]  _emptyArray = new T[0];

// 其他内容

}

// C# Code

// Adds the given object to the end of this list. The size of the list is

// increased by one. If required, the capacity of the list is doubled

// before adding the new element.

//

//扩容时翻倍

public void Add(T item) {

if (_size == _items.Length)

EnsureCapacity(_size + 1);

_items[_size++] = item;

_version++;

}

// Ensures that the capacity of this list is at least the given minimum

// value. If the currect capacity of the list is less than min, the

// capacity is increased to twice the current capacity or to min,

// whichever is larger.

private void EnsureCapacity(int min) {

if (_items.Length < min) {

int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;

// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.

// Note that this check works even when _items.Length overflowed thanks to the (uint) cast

if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;

if (newCapacity < min) newCapacity = min;

Capacity = newCapacity;

}

}

// Gets and sets the capacity of this list.  The capacity is the size of

// the internal array used to hold items.  When set, the internal

// array of the list is reallocated to the given capacity.

//

public int Capacity {

get {

Contract.Ensures(Contract.Result<int>() >= 0);

return _items.Length;

}

set {

if (value < _size) {

ThrowHelper.ThrowArgumentOutOfRangeException(

ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);

}

Contract.EndContractBlock();

if (value != _items.Length) {

if (value > 0) {

T[] newItems = new T[value];

if (_size > 0) {

Array.Copy(_items, 0, newItems, 0, _size);

}

_items = newItems;

}

else {

_items = _emptyArray;

}

}

}

}

C# 中 List默认的容量其实是4,所以最好还是初始化容量吧,可以想象,如果一个列表里面有129个元素,那么代码中对Capacity的调用会有很多次,4->8->16->32->64->128->256,不但最后的容量中产生了大量的浪费,前面的一堆对象也都需要GC搞定了。也就是252个对象。浪费还是很严重的。

// Removes the element at the given index. The size of the list is

// decreased by one.

public bool Remove(T item) {

int index = IndexOf(item);

if (index >= 0) {

RemoveAt(index);

return true;

}

return false;

}

// Returns the index of the first occurrence of a given value in a range of

// this list. The list is searched forwards from beginning to end.

// The elements of the list are compared to the given value using the

// Object.Equals method.

//

// This method uses the Array.IndexOf method to perform the

// search.

//

public int IndexOf(T item) {

Contract.Ensures(Contract.Result<int>() >= -1);

Contract.Ensures(Contract.Result<int>() < Count);

return Array.IndexOf(_items, item, 0, _size);

}

// Array.cs

public static int IndexOf<T>(T[] array, T value, int startIndex, int count) {

if (array==null) {

throw new ArgumentNullException("array");

}

if (startIndex < 0 || startIndex > array.Length ) {

throw new ArgumentOutOfRangeException("startIndex",

Environment.GetResourceString("ArgumentOutOfRange_Index"));

}

if (count < 0 || count > array.Length - startIndex) {

throw new ArgumentOutOfRangeException("count",

Environment.GetResourceString("ArgumentOutOfRange_Count"));

}

Contract.Ensures(Contract.Result<int>() < array.Length);

Contract.EndContractBlock();

return EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count);

}

// Removes the element at the given index. The size of the list is

// decreased by one.

public void RemoveAt(int index) {

if ((uint)index >= (uint)_size) {

ThrowHelper.ThrowArgumentOutOfRangeException();

}

Contract.EndContractBlock();

_size--;

if (index < _size) {

Array.Copy(_items, index + 1, _items, index, _size - index);

}

_items[_size] = default(T);

_version++;

}

从代码来看,remove操作优先看的是能否找到该元素,如果能找到,将其移除,返回True,否则,返回false

C#的索引方法有点复杂,点到EqualityComparer里面看了一下索引的方法,这也是C#跟Java的不同之处了,Java的泛型里面是不能写入Primitive类型的,因为Primitive类型其实是不继承Object的,所以无法调用其中的equals方法。

但是C#是支持的,所以,会判断元类型的Type,然后选取对应的Equals方法。

现在回头看下RemoveAt方法,该方法仍然会调用Array.Copy操作,所以,可想而知删除操作的复杂度了,内存中平均删除一个元素,要移动n/2个元素,复杂度为O(n)

而RemoveAll方法本身是复杂度为O(n)的,所以最好不要在循环中写Remove操作吧。

C#List源码的更多相关文章

  1. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  2. C# ini文件操作【源码下载】

    介绍C#如何对ini文件进行读写操作,C#可以通过调用[kernel32.dll]文件中的 WritePrivateProfileString()和GetPrivateProfileString()函 ...

  3. 【原】FMDB源码阅读(三)

    [原]FMDB源码阅读(三) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 FMDB比较优秀的地方就在于对多线程的处理.所以这一篇主要是研究FMDB的多线程处理的实现.而 ...

  4. 从源码看Azkaban作业流下发过程

    上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...

  5. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  6. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  7. 多线程爬坑之路-Thread和Runable源码解析之基本方法的运用实例

    前面的文章:多线程爬坑之路-学习多线程需要来了解哪些东西?(concurrent并发包的数据结构和线程池,Locks锁,Atomic原子类) 多线程爬坑之路-Thread和Runable源码解析 前面 ...

  8. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  9. 【深入浅出jQuery】源码浅析--整体架构

    最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐 ...

  10. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

随机推荐

  1. java之try、catch、finally

    结论:try和catch相当于程序分支,finally块中不会改变变量的指针(引用地址):和final修饰的变量类似. public class Test { public static AreaRQ ...

  2. 概念吓死人的webservice

    前倾提要:这是我七拼八凑,自己用手打出来的头一篇了!都是别人的想法,我抄袭的,我坦白,我这只是总结一下觉得有用的 本来题目想叫(1)REST API 和WebService(2)REST 样式和 SO ...

  3. 7-安装Spark

    1.Apache Hadoop2.7中的YARN与JAVA8有冲突,如果想要使用spark on yarn,首先需要在yarn-site.xml中配置如下项: <property> < ...

  4. 2018-2019-1 20165205 ch02 课下作业

    ch02 课下作业 2.96 代码 #include <stdio.h> #include <stdlib.h> typedef unsigned float_bits; fl ...

  5. win10 安装 oracle 11g

    在安装文件的/stage/cvu文件夹下面找到文件 cvu_prereq.xml文件 64位添加红色部分 32位添加蓝色部分   ............... </OPERATING_SYST ...

  6. rpm梳理

  7. C# 对Excel操作与分析

    今天帮现在饿公司写个工具,要动态读excel上的ip地址与端口号,来更改IE的代理地址,由于好久没写Excel的操作了,只能查阅以前的项目,总结一下: 首先我们要引用我们的com接口的excelMic ...

  8. halcon批量读取图片

    以前这个代码都是自己写,不仅繁琐,而且容易忘记.其实Halcon中提供了相关的方法.记录一下吧,其实很简单. 读取一个文件夹下的所有图片[助手]>[打开新的image acquisition ] ...

  9. centos实现永久修改hostname

    前言 介绍一下centos的两种修改hostname的方式. 查看hostname [root@slave02 ~]# hostname slave02 临时性修改 [root@slave02 ~]# ...

  10. ReactiveX 学习笔记(20)使用 RxJava + RxBinding 进行 GUI 编程

    课题 程序界面由3个文本编辑框和1个文本标签组成. 要求文本标签实时显示3个文本编辑框所输入的数字之和. 文本编辑框输入的不是合法数字时,将其值视为0. 3个文本编辑框的初值分别为1,2,3. 创建工 ...