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. 启动kafka时报scala相关错误:java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc()

    1.报错现象: 启动kafka的时候启动失败,并且会报告下面的错误: java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc(Ljava/lang/ ...

  2. 知识点:图说 Mysql 权限管理

    图: #授权表 user #该表放行的权限,针对:所有数据,所有库下所有表,以及表下的所有字段 db #该表放行的权限,针对:某一数据库,该数据库下的所有表,以及表下的所有字段 tables_priv ...

  3. centos7安装 owncloud注意事项

    要关于selinux 用来存放文件的目录权限要修改 chown -R apache:apache my.cnf里的binlog_format=mixed前面的注释去掉,不然报mysql错!

  4. Apollo配置中心

    背景: 当前我们项目,所有的配置基本都是通过本地properties 文件进行配置的,比如ip地址.端口.消息中间件和数据库连接的各种参数,当我们需要切换环境或调整参数的时候,我们必须手动的修改这些配 ...

  5. 1. redis安装(windows)

    Redis在windows下安装过程 转载自(http://www.cnblogs.com/M-LittleBird/p/5902850.html)   一.下载windows版本的Redis 去官网 ...

  6. 深度学习原理与框架-递归神经网络-RNN_exmaple(代码) 1.rnn.BasicLSTMCell(构造基本网络) 2.tf.nn.dynamic_rnn(执行rnn网络) 3.tf.expand_dim(增加输入数据的维度) 4.tf.tile(在某个维度上按照倍数进行平铺迭代) 5.tf.squeeze(去除维度上为1的维度)

    1. rnn.BasicLSTMCell(num_hidden) #  构造单层的lstm网络结构 参数说明:num_hidden表示隐藏层的个数 2.tf.nn.dynamic_rnn(cell, ...

  7. 一个free异常引发的异常

    有同事反馈说自己的线程不工作,查看堆栈发现其打印如下: # # # # # # # # , info= # <signal handler called> # # # # # # # , ...

  8. LevelDB源码分析-Get

    Get LevelDB提供了Get接口用于给定key的查找: Status DBImpl::Get(const ReadOptions &options, const Slice &k ...

  9. [Shell]Bash变量:自定义变量 & 环境变量 & 位置参数变量 & 预定义变量

    --------------------------------------------------------------------------------- 变量是计算机内存的单元,其中存放的值 ...

  10. grains和pillar的联合使用

    在编写sls文件的时候,对于不同的客户端,在配置管理的时候,其安装的环境,配置文件和启动的服务都相同: 如果完全是不同的环境,建议写单独的sls文件,不要混合在一起; 如果是相同的环境,只不过对于不同 ...