您的位置:首页 > 理论基础 > 数据结构算法

基本数据结构解析之ArrayList

2008-11-29 19:01 751 查看

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: