常用操作的复杂度分析

Contains

该方法是一个O(n)的方法,是根据顺序依次遍历整个列表的,观看源码,跟JAVA还是有不少分别的,在上一篇中就有发现,因为C#对Primitive类型是有处理的,所以跟JAVA代码略有不同

// Contains returns true if the specified element is in the List.
// It does a linear, O(n) search. Equality is determined by calling
// 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;
}
}

代码中使用了EqualityComparer,就是对Primitive类型进行了额外的处理,否则他们并非继承Object,则没有Equals和Hashcode方法。

以下是JAVA的代码

/**
* Returns <tt>true</tt> if this list contains the specified element.
* More formally, returns <tt>true</tt> if and only if this list contains
* at least one element <tt>e</tt> such that
* <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
*
* @param o element whose presence in this list is to be tested
* @return <tt>true</tt> if this list contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
} /**
* Returns the index of the first occurrence of the specified element
* in this list, or -1 if this list does not contain the element.
* More formally, returns the lowest index <tt>i</tt> such that
* <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*/
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}

Java是通过调用Object的equals方法来实现的,也从侧面说明了为什么JAVA的泛型其实是不支持primitive类型了。

另外还有一个细节,C#对Contains是针对泛型的方法,而JAVA是针对Object的方法。

不过忽略掉Primitive的泛型,JAVA代码的简洁上,比C#确实要好些,用起来麻烦一些

Insert

Java中的Insert是一个重载方法,其实就是对Add方法的重载

C#则是额外抽象了一个方法叫做Insert,因为Insert指定了索引,所以,insert操作对数组是有copy操作的,所以复杂度为O(n)

而且同时有可能因为插入造成数组大量的copy从而进行Capacity的倍增

// Inserts an element into this list at a given index. The size of the list
// is increased by one. If required, the capacity of the list is doubled
// before inserting the new element.
//
public void Insert(int index, T item) {
// Note that insertions at the end are legal.
if ((uint) index > (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_ListInsert);
}
Contract.EndContractBlock();
if (_size == _items.Length) EnsureCapacity(_size + 1);
if (index < _size) {
Array.Copy(_items, index, _items, index + 1, _size - index);
}
_items[index] = item;
_size++;
_version++;
}

这里使用了ThrowHelper这个静态类,最开始,还以为是他们为了让代码可读,所以使用工厂方法,更易用

但是后来发现不是这门回事,是为了在中间层次优化集合类而做的。

// This file defines an internal class used to throw exceptions in BCL code.
// The main purpose is to reduce code size.
//
// The old way to throw an exception generates quite a lot IL code and assembly code.
// Following is an example:
// C# source
// throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
// IL code:
// IL_0003: ldstr "key"
// IL_0008: ldstr "ArgumentNull_Key"
// IL_000d: call string System.Environment::GetResourceString(string)
// IL_0012: newobj instance void System.ArgumentNullException::.ctor(string,string)
// IL_0017: throw
// which is 21bytes in IL.
//
// So we want to get rid of the ldstr and call to Environment.GetResource in IL.
// In order to do that, I created two enums: ExceptionResource, ExceptionArgument to represent the
// argument name and resource name in a small integer. The source code will be changed to
// ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key, ExceptionResource.ArgumentNull_Key);
//
// The IL code will be 7 bytes.
// IL_0008: ldc.i4.4
// IL_0009: ldc.i4.4
// IL_000a: call void System.ThrowHelper::ThrowArgumentNullException(valuetype System.ExceptionArgument)
// IL_000f: ldarg.0
//
// This will also reduce the Jitted code size a lot.
//
// It is very important we do this for generic classes because we can easily generate the same code
// multiple times for different instantiation.
//
// <

在IL层次上,如果使用throw关键字,那么编译出来的IL代码很多,然后,如果使用静态方法,他们IL大量代码将被重用,从而减少IL代码的大小。

InsertRange

InsertRange 方法,在指定位置插入若干元素,该方法和JAVA中的addAll方法有些类似,不过不同的是,C#中的插入的参数是必须实现IEnumerable< T >接口的,但是Java中,参数是必须实现Collection接口的,这也导致了两者方法中的不同

C# 针对Collection,对操作进行了优化,在内存copy上,只是进行了一次,但是如果是自己的类实现了IEnumerable接口的话,操作复杂度则大大增加,会频繁调用insert操作

自己实现了IEnumerable接口的话,切忌使用insertRange方法,复杂度太高

// Inserts the elements of the given collection at a given index. If
// required, the capacity of the list is increased to twice the previous
// capacity or the new size, whichever is larger. Ranges may be added
// to the end of the list by setting index to the List's size.
//
public void InsertRange(int index, IEnumerable<T> collection) {
if (collection==null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
} if ((uint)index > (uint)_size) {
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
}
Contract.EndContractBlock(); ICollection<T> c = collection as ICollection<T>;
if( c != null ) { // if collection is ICollection<T>
int count = c.Count;
if (count > 0) {
EnsureCapacity(_size + count);
if (index < _size) {
Array.Copy(_items, index, _items, index + count, _size - index);
} // If we're inserting a List into itself, we want to be able to deal with that.
if (this == c) {
// Copy first part of _items to insert location
Array.Copy(_items, 0, _items, index, index);
// Copy last part of _items back to inserted location
Array.Copy(_items, index+count, _items, index*2, _size-index);
}
else {
T[] itemsToInsert = new T[count];
c.CopyTo(itemsToInsert, 0);
itemsToInsert.CopyTo(_items, index);
}
_size += count;
}
}
else {
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Insert(index++, en.Current);
}
}
}
_version++;
}

SynchronizedList

这个类实现了IList接口,只是所有的方法都加上了同步操作,看代码结构就知道是典型的代理模式啊

internal class SynchronizedList : IList<T> {
private List<T> _list;
private Object _root; /// other
}

在初始化的时候,使用的lock用的对象则是List中的SyncRoot,这样每次增加了同步操作,保证了线程的安全性

Java的线程安全的List是Vector,和C#不同的是,没有用代理模式,而是所有方法全部重写了,仍然是ArrayList一个结构,不同的是方法上都加了synchronized

以下为List源码地址

List源码

Array源码

C# List源码分析(二)的更多相关文章

  1. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  2. 框架-springmvc源码分析(二)

    框架-springmvc源码分析(二) 参考: http://www.cnblogs.com/leftthen/p/5207787.html http://www.cnblogs.com/leftth ...

  3. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

  4. 十、Spring之BeanFactory源码分析(二)

    Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...

  5. Vue源码分析(二) : Vue实例挂载

    Vue源码分析(二) : Vue实例挂载 author: @TiffanysBear 实例挂载主要是 $mount 方法的实现,在 src/platforms/web/entry-runtime-wi ...

  6. 多线程之美8一 AbstractQueuedSynchronizer源码分析<二>

    目录 AQS的源码分析 该篇主要分析AQS的ConditionObject,是AQS的内部类,实现等待通知机制. 1.条件队列 条件队列与AQS中的同步队列有所不同,结构图如下: 两者区别: 1.链表 ...

  7. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  8. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  9. ConcurrenHashMap源码分析(二)

    本篇博客的目录: 一:put方法源码 二:get方法源码 三:rehash的过程 四:总结 一:put方法的源码 首先,我们来看一下segment内部类中put方法的源码,这个方法它是segment片 ...

  10. spark(1.1) mllib 源码分析(二)-相关系数

    原创文章,转载请注明: 转载自http://www.cnblogs.com/tovin/p/4024733.html 在spark mllib 1.1版本中增加stat包,里面包含了一些统计相关的函数 ...

随机推荐

  1. HDU 1429--胜利大逃亡(续)【BFS &amp;&amp; 状态压缩】

    胜利大逃亡(续) Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  2. 怎样手动的干净的删除linux上的ORACLE数据库

    近期在用VMWARE虚拟机做ORACLE的数据库实验.我们都知道在WINDOWS上,我能够到加入删除程序里去自己主动删除已经安装的全部的应用程序.可是在LINUX上没有这个服务能够进行自己主动的删除. ...

  3. 公布IOS产品被拒后怎样再上传新公布包

    问题描写叙述: 前两天提交公司产品2.0.7版本号到苹果审核,昨天提示被拒绝. 被拒原因就不描写叙述了. 我们经过改动后.又一次打包上传,但是怎么也提交不了.由于在苹果后台上已经存在2.0.7版本号的 ...

  4. Lua 与C/C++ 交互系列:注冊枚举enum到Lua Code中

    在Lua Code中注冊C/C++的枚举很easy,就像注冊全局变量一样.我们使用枚举名称作为命名空间,来避免注冊的枚举发生冲突.注冊的枚举存储在全局环境(线程环境)中. 当在Lua Code中訪问枚 ...

  5. 远程桌面授权server没有提供许可证问题解决方法

    今天远程server报如图所看到的错误,网上查找的方法 方法一:(亲測有效) mstsc /V:192.168.0.3 /admin  方法二:(因为server正在使用中,未作測试) 删除远程桌面服 ...

  6. 线程同步、死锁和通信——Java多线程(二)

    一.多线程同步 上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题. 1.同步代码块 class ...

  7. Value Stewardship Over Showmanship

     Value Stewardship Over Showmanship Barry Hawkins WHEn An ARCHiTECT EnTERS A pRojECT, there is an u ...

  8. luogu2606 排列计数

    题目大意 求满足下列条件的排列$P$的数量:$\forall P_i, P_i>P_{\lfloor \frac{i}{2}\rfloor}$. 思路 从下标入手 反过来想,也就是对$\fora ...

  9. luogu2014 选课 背包类树形DP

    题目大意:有N门功课,每门课有个学分,每门课有一门或没有直接先修课(若课程a是课程b的先修课即只有学完了课程a,才能学习课程b).一个学生要从这些课程里选择M门课程学习,问他能获得的最大学分是多少? ...

  10. 向量叉乘 Cross product

    参考:Wiki Cross product