基本数据结构解析之ArrayList
ArrayList:
使用大小可按需动态增加的数组实现 IList 接口。(From MSDN)
初始化, 内部默认是4的Capacity, 还是采用Object存储
1: private const int _defaultCapacity = 4;
2: private Object[] _items;
3: private static readonly Object[] emptyArray = new Object[0];
4:
5: // Note: this constructor is a bogus constructor that does nothing
6: // and is for use only with SyncArrayList.
7: internal ArrayList( bool trash )
8: {
9: }
10:
11: // Constructs a ArrayList. The list is initially empty and has a capacity
12: // of zero. Upon adding the first element to the list the capacity is
13: // increased to _defaultCapacity, and then increased in multiples of two as required.
14: public ArrayList() {
15: _items = emptyArray;
16: }
17:
18: // Constructs a ArrayList with a given initial capacity. The list is
19: // initially empty, but will have room for the given number of elements
20: // before any reallocations are required.
21: //
22: public ArrayList(int capacity) {
23: if (capacity < 0) throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "capacity"));
24: _items = new Object[capacity];
25: }
26:
27: // Constructs a ArrayList, copying the contents of the given collection. The
28: // size and capacity of the new list will both be equal to the size of the
29: // given collection.
30: //
31: public ArrayList(ICollection c) {
32: if (c==null)
33: throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection"));
34: _items = new Object[c.Count];
35: AddRange(c);
36: }
Capacity 比较有趣的是如果设置新的Capacity, 如果大于原有的length则会发生
1. 建立新的以新的Capacity为容量大小的Object数组
2. 将原有数据拷贝到新的数组上去
3. 将原有引用指向新的Object数组上去
1: // Gets and sets the capacity of this list. The capacity is the size of
2: // the internal array used to hold items. When set, the internal
3: // array of the list is reallocated to the given capacity.
4: //
5: public virtual int Capacity {
6: get { return _items.Length; }
7: set {
8: // We don't want to update the version number when we change the capacity.
9: // Some existing applications have dependency on this.
10: if (value != _items.Length) {
11: if (value < _size) {
12: throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
13: }
14:
15: if (value > 0) {
16: Object[] newItems = new Object[value];
17: if (_size > 0) {
18: Array.Copy(_items, 0, newItems, 0, _size);
19: }
20: _items = newItems;
21: }
22: else {
23: _items = new Object[_defaultCapacity];
24: }
25: }
26: }
ListWrapper 把一个IList转换为ArrayList
1: // Creates a ArrayList wrapper for a particular IList. This does not
2: // copy the contents of the IList, but only wraps the ILIst. So any
3: // changes to the underlying list will affect the ArrayList. This would
4: // be useful if you want to Reverse a subrange of an IList, or want to
5: // use a generic BinarySearch or Sort method without implementing one yourself.
6: // However, since these methods are generic, the performance may not be
7: // nearly as good for some operations as they would be on the IList itself.
8: //
9: public static ArrayList Adapter(IList list) {
10: if (list==null)
11: throw new ArgumentNullException("list");
12: return new IListWrapper(list);
13: }
添加元素, 在超出容量时还是会Double原来的Size
1: // Adds the given object to the end of this list. The size of the list is
2: // increased by one. If required, the capacity of the list is doubled
3: // before adding the new element.
4: //
5: public virtual int Add(Object value) {
6: if (_size == _items.Length) EnsureCapacity(_size + 1);
7: _items[_size] = value;
8: _version++;
9: return _size++;
10: }
11:
12: // Ensures that the capacity of this list is at least the given minimum
13: // value. If the currect capacity of the list is less than min, the
14: // capacity is increased to twice the current capacity or to min,
15: // whichever is larger.
16: private void EnsureCapacity(int min) {
17: if (_items.Length < min) {
18: int newCapacity = _items.Length == 0? _defaultCapacity: _items.Length * 2;
19: if (newCapacity < min) newCapacity = min;
20: Capacity = newCapacity;
21: }
22: }
批量插入元素, 和插入元素类似
1: // Adds the elements of the given collection to the end of this list. If
2: // required, the capacity of the list is increased to twice the previous
3: // capacity or the new size, whichever is larger.
4: //
5: public virtual void AddRange(ICollection c) {
6: InsertRange(_size, c);
7: }
8:
9: // Inserts the elements of the given collection at a given index. If
10: // required, the capacity of the list is increased to twice the previous
11: // capacity or the new size, whichever is larger. Ranges may be added
12: // to the end of the list by setting index to the ArrayList's size.
13: //
14: public virtual void InsertRange(int index, ICollection c) {
15: if (c==null)
16: throw new ArgumentNullException("c", Environment.GetResourceString("ArgumentNull_Collection"));
17: if (index < 0 || index > _size) throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
18: int count = c.Count;
19: if (count > 0) {
20: EnsureCapacity(_size + count);
21: // shift existing items
22: if (index < _size) {
23: Array.Copy(_items, index, _items, index + count, _size - index);
24: }
25:
26: Object[] itemsToInsert = new Object[count];
27: c.CopyTo(itemsToInsert, 0);
28: itemsToInsert.CopyTo(_items, index);
29: _size += count;
30: _version++;
31: }
32: }
二分查找
1: // Searches a section of the list for a given element using a binary search
2: // algorithm. Elements of the list are compared to the search value using
3: // the given IComparer interface. If comparer is null, elements of
4: // the list are compared to the search value using the IComparable
5: // interface, which in that case must be implemented by all elements of the
6: // list and the given search value. This method assumes that the given
7: // section of the list is already sorted; if this is not the case, the
8: // result will be incorrect.
9: //
10: // The method returns the index of the given value in the list. If the
11: // list does not contain the given value, the method returns a negative
12: // integer. The bitwise complement operator (~) can be applied to a
13: // negative result to produce the index of the first element (if any) that
14: // is larger than the given search value. This is also the index at which
15: // the search value should be inserted into the list in order for the list
16: // to remain sorted.
17: //
18: // The method uses the Array.BinarySearch method to perform the
19: // search.
20: //
21: public virtual int BinarySearch(int index, int count, Object value, IComparer comparer) {
22: if (index < 0 || count < 0)
23: throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
24: if (_size - index < count)
25: throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
26:
27: return Array.BinarySearch((Array)_items, index, count, value, comparer);
28: }
29:
30: public virtual int BinarySearch(Object value)
31: {
32: return BinarySearch(0,Count,value,null);
33: }
34:
35: public virtual int BinarySearch(Object value, IComparer comparer)
36: {
37: return BinarySearch(0,Count,value,comparer);
38: }
调用Array.BinarySearch, 关于BinarySearch的内容较多,您可以查看MSDN, 还有这里看源码
不知道二分查找?看这里
这里的原理: 如果有Comparer则调用Comparer进行二分查找.如果是Comparer.Default在运行时查看类型,采用Switch进行处理,调用对应类型ArrayHelper<KIND>.BinarySearchBitwiseEquals,
1: // Searches a section of an array for a given element using a binary search
2: // algorithm. Elements of the array are compared to the search value using
3: // the IComparable interface, which must be implemented by all
4: // elements of the array and the given search value. This method assumes
5: // that the array is already sorted according to the IComparable
6: // interface; if this is not the case, the result will be incorrect.
7: //
8: // The method returns the index of the given value in the array. If the
9: // array does not contain the given value, the method returns a negative
10: // integer. The bitwise complement operator (~) can be applied to a
11: // negative result to produce the index of the first element (if any) that
12: // is larger than the given search value.
13: //
14: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
15: public static int BinarySearch(Array array, int index, int length, Object value) {
16: return BinarySearch(array, index, length, value, null);
17: }
18:
19: // Searches an array for a given element using a binary search algorithm.
20: // Elements of the array are compared to the search value using the given
21: // IComparer interface. If comparer is null, elements of the
22: // array are compared to the search value using the IComparable
23: // interface, which in that case must be implemented by all elements of the
24: // array and the given search value. This method assumes that the array is
25: // already sorted; if this is not the case, the result will be incorrect.
26: //
27: // The method returns the index of the given value in the array. If the
28: // array does not contain the given value, the method returns a negative
29: // integer. The bitwise complement operator (~) can be applied to a
30: // negative result to produce the index of the first element (if any) that
31: // is larger than the given search value.
32: //
33: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
34: public static int BinarySearch(Array array, Object value, IComparer comparer) {
35: if (array==null)
36: throw new ArgumentNullException("array");
37: int lb = array.GetLowerBound(0);
38: return BinarySearch(array, lb, array.Length, value, comparer);
39: }
40:
41: // Searches a section of an array for a given element using a binary search
42: // algorithm. Elements of the array are compared to the search value using
43: // the given IComparer interface. If comparer is null,
44: // elements of the array are compared to the search value using the
45: // IComparable interface, which in that case must be implemented by
46: // all elements of the array and the given search value. This method
47: // assumes that the array is already sorted; if this is not the case, the
48: // result will be incorrect.
49: //
50: // The method returns the index of the given value in the array. If the
51: // array does not contain the given value, the method returns a negative
52: // integer. The bitwise complement operator (~) can be applied to a
53: // negative result to produce the index of the first element (if any) that
54: // is larger than the given search value.
55: //
56: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
57: public static int BinarySearch(Array array, int index, int length, Object value, IComparer comparer) {
58: if (array==null)
59: throw new ArgumentNullException("array");
60: int lb = array.GetLowerBound(0);
61: if (index < lb || length < 0)
62: throw new ArgumentOutOfRangeException((index<lb ? "index" : "length"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
63: if (array.Length - (index - lb) < length)
64: throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
65: if (array.Rank != 1)
66: throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
67:
68: if (comparer == null) comparer = Comparer.Default;
69: if (comparer == Comparer.Default) {
70: int retval;
71: bool r = TrySZBinarySearch(array, index, length, value, out retval);
72: if (r)
73: return retval;
74: }
75:
76: int lo = index;
77: int hi = index + length - 1;
78: Object[] objArray = array as Object[];
79: if(objArray != null) {
80: while (lo <= hi) {
81: // i might overflow if lo and hi are both large positive numbers.
82: int i = GetMedian(lo, hi);
83:
84: int c;
85: try {
86: c = comparer.Compare(objArray[i], value);
87: }
88: catch (Exception e) {
89: throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e);
90: }
91: catch {
92: throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"));
93: }
94: if (c == 0) return i;
95: if (c < 0) {
96: lo = i + 1;
97: }
98: else {
99: hi = i - 1;
100: }
101: }
102: }
103: else {
104: while (lo <= hi) {
105: int i = GetMedian(lo, hi);
106:
107: int c;
108: try {
109: c = comparer.Compare(array.GetValue(i), value);
110: }
111: catch (Exception e) {
112: throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"), e);
113: }
114: catch {
115: throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_IComparerFailed"));
116: }
117: if (c == 0) return i;
118: if (c < 0) {
119: lo = i + 1;
120: }
121: else {
122: hi = i - 1;
123: }
124: }
125: }
126: return ~lo;
127: }
Clear, Clone, Contains 同上
CopyTo, 跟Clone的方式类似,不同的是增加了索引拷贝的方式
锁定数组, 可以对IList和ArrayList进行锁定,添加和删除操作都会失败,但是替换操作依然可以执行, 是这样的吗?
1: // Returns a list wrapper that is fixed at the current size. Operations
2: // that add or remove items will fail, however, replacing items is allowed.
3: //
4: public static IList FixedSize(IList list) {
5: if (list==null)
6: throw new ArgumentNullException("list");
7: return new FixedSizeList(list);
8: }
9:
10: // Returns a list wrapper that is fixed at the current size. Operations
11: // that add or remove items will fail, however, replacing items is allowed.
12: //
13: public static ArrayList FixedSize(ArrayList list) {
14: if (list==null)
15: throw new ArgumentNullException("list");
16: return new FixedSizeArrayList(list);
17: }
Reverse
首先会调用mscorworks中的方法来对对应的类型利用泛型的方式进行翻转。如果找不到对应的类型(即内建的基本类型)。则按首尾交换的原则进行翻转
调用方式如下查看代码
1: // Reverses the elements in this list.
2: public virtual void Reverse() {
3: Reverse(0, Count);
4: }
5:
6: // Reverses the elements in a range of this list. Following a call to this
7: // method, an element in the range given by index and count
8: // which was previously located at index i will now be located at
9: // index index + (index + count - i - 1).
10: //
11: // This method uses the Array.Reverse method to reverse the
12: // elements.
13: //
14: public virtual void Reverse(int index, int count) {
15: if (index < 0 || count < 0)
16: throw new ArgumentOutOfRangeException((index<0 ? "index" : "count"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
17: if (_size - index < count)
18: throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
19: Array.Reverse(_items, index, count);
20: _version++;
21: }
22:
23: // Reverses the elements in a range of an array. Following a call to this
24: // method, an element in the range given by index and count
25: // which was previously located at index i will now be located at
26: // index index + (index + count - i - 1).
27: // Reliability note: This may fail because it may have to box objects.
28: //
29: [ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
30: public static void Reverse(Array array, int index, int length) {
31: if (array==null)
32: throw new ArgumentNullException("array");
33: if (index < array.GetLowerBound(0) || length < 0)
34: throw new ArgumentOutOfRangeException((index<0 ? "index" : "length"), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
35: if (array.Length - (index - array.GetLowerBound(0)) < length)
36: throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
37: if (array.Rank != 1)
38: throw new RankException(Environment.GetResourceString("Rank_MultiDimNotSupported"));
39:
40: bool r = TrySZReverse(array, index, length);
41: if (r)
42: return;
43:
44: int i = index;
45: int j = index + length - 1;
46: Object[] objArray = array as Object[];
47: if (objArray!=null) {
48: while (i < j) {
49: Object temp = objArray[i];
50: objArray[i] = objArray[j];
51: objArray[j] = temp;
52: i++;
53: j--;
54: }
55: }
56: else {
57: while (i < j) {
58: Object temp = array.GetValue(i);
59: array.SetValue(array.GetValue(j), i);
60: array.SetValue(temp, j);
61: i++;
62: j--;
63: }
64: }
65: }
66: static void Reverse(KIND array[], UINT32 index, UINT32 count) {
67: LEAF_CONTRACT;
68:
69: _ASSERTE(array != NULL);
70: if (count == 0) {
71: return;
72: }
73: UINT32 i = index;
74: UINT32 j = index + count - 1;
75: while(i < j) {
76: KIND temp = array[i];
77: array[i] = array[j];
78: array[j] = temp;
79: i++;
80: j--;
81: }
82: }
SetValue
通过读取index的索引处的指针, 调用内部的实现来设置值
1: InternalGetReference(&elemref, 3, pIndices);
2: InternalSetValue(&elemref,value);
3: [MethodImplAttribute(MethodImplOptions.InternalCall)]
4: // reference to TypedReference is banned, so have to pass result as pointer
5: private unsafe extern void InternalGetReference(void * elemRef, int rank, int * pIndices);
6:
7: [MethodImplAttribute(MethodImplOptions.InternalCall)]
8: private unsafe extern static void InternalSetValue(void * target, Object value);
Sort
首先查找内部底层实现中对应类型的快速排序,如果没有,则在BCL层次利用ICompare接口实现进行快速排序
代码太大,查看
CLR/SRC/SYSTEM/ArrayList.cs, Array.cs
CLR/SRC/VM/Array.cpp, ComArrayHelper.cpp