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. IIS 添加 MIME

    参考:https://blog.brain1981.com/727.html 在项目的  Web.Config 里下添加如下段落即可: <?xml version="1.0" ...

  2. Unity Shader Graph(一)初次尝试

    软件环境 Unity Version: 2018.1.2f1 边缘发光材质效果 创建工程 打开Unity并创建一个新工程 安装依赖项 Window -> Package Manager打开包管理 ...

  3. js 常用代码片段

    一.预加载图像 如果你的网页中需要使用大量初始不可见的(例如,悬停的)图像,那么可以预加载这些图像. function preloadImages(){ for(var i=0;i<argume ...

  4. debug protractor

    HTAir:protractor-cucumber-typescript kbladewht$ node --inspect-brk=0.0.0.0:1229 node_modules/protrac ...

  5. 协程,greenlet,gevent

    """ 协程 """ ''' 协程: 类似于一个可以暂停的函数,可以多次传入数据,可以多次返回数据 协程是可交互的 耗资源大小:进程 --& ...

  6. boost安装缺少libboost_iostreams.so

    编译安装boost库: 1 ./bootstrap.sh 2 ./bjam 3 ./b2 install 但安装boosth后,发现缺少libboost_iostreams.so库,后发现boost库 ...

  7. python学习笔记_week27

    search import time import random def cal_time(func): def wrapper(*args, **kwargs): t1 = time.time() ...

  8. centos下安装djangobb

    曾经在freenas虚拟环境下安装过djangobb,因为要安装的依赖文件太多,最后没有安装成功. 今晚在centos6.9 下,先创建了虚拟环境,然后照着官方网站的快速安装指南,安装后也运行不了,后 ...

  9. python大法好——递归、内置函数、函数进阶

    1.递归(自己干自己) def fun(n): n=n/2 print(n) if(n>2) fun(n) #函数调用 fun(10) 结果是5 2 1 0 递归的执行过程:递归执行到最里面一层 ...

  10. python中configpraser模块

    configparser   模块 解析配置文件模块 什么是配置文件? 用于编写程序的配置信息的文件 什么是配置信息? 为了提高程序的扩展性 #configparser模块的使用 #首先我们需要知道配 ...