基本数据结构解析之Stack & Queue

Stack:

遵循后进先出原则,最后进来的第一个出去,查看详细(English)中文

参考代码 CLR/SRC/BCL/System/Stack.cs

构造函数(初始化)

Stack() / Stack(int initialCapacity) / Stack(ICollection col) : this((col==null ? 32 : col.Count))

在Array中采用Object[]作为数据容器,同时会有一个默认的defaultCapbility = 10,如果initialCapacity 小于 defaultCapbility或者没有设置默认的capbility, 则初始化容量为10的Object数组

对应的代码:

   1: private Object[] _array;     // Storage for stack elements
   2: private int _size;           // Number of items in the stack.
   3: private int _version;        // Used to keep enumerator in sync w/ collection.
   4:  
   5: private const int _defaultCapacity = 10;
   6:  
   7: public Stack() {
   8:     _array = new Object[_defaultCapacity];
   9:     _size = 0;
  10:     _version = 0;
  11: }
  12:  
  13: // Create a stack with a specific initial capacity.  The initial capacity
  14: // must be a non-negative number.
  15: public Stack(int initialCapacity) {
  16:     if (initialCapacity < 0)
  17:         throw new ArgumentOutOfRangeException("initialCapacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  18:     if (initialCapacity < _defaultCapacity)
  19:         initialCapacity = _defaultCapacity;  // Simplify doubling logic in Push.
  20:     _array = new Object[initialCapacity];
  21:     _size = 0;
  22:     _version = 0;
  23: }

Push/Pop

Push: 如果数据达到最大容量,则分配到容量*2新的数组,并将原来的数据拷贝到新数组, 之后将栈顶设为对应的值,而后栈顶索引自加

   1: // Pushes an item to the top of the stack.
   2: // 
   3: public virtual void Push(Object obj) {
   4:     if (_size == _array.Length) {
   5:         Object[] newArray = new Object[2*_array.Length];
   6:         Array.Copy(_array, 0, newArray, 0, _size);
   7:         _array = newArray;
   8:     }
   9:     _array[_size++] = obj;
  10:     _version++;
  11: }

为了验证内存中的数据是否真如逻辑上所说,我在这里用WINDBG做了一下验证,有兴趣的读者可以去看看。

Pop: 将栈顶设为null, 索引自减

   1: // Pops an item from the top of the stack.  If the stack is empty, Pop
   2: // throws an InvalidOperationException.
   3: public virtual Object Pop() {
   4:     if (_size == 0)
   5:         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyStack"));
   6:     _version++;
   7:     Object obj = _array[--_size];
   8:     _array[_size] = null;     // Free memory quicker.
   9:     return obj;
  10: }

Contains - 按索引进行顺序比较

   1: public virtual bool Contains(Object obj) {
   2:     int count = _size;
   3:  
   4:     while (count-- > 0) {
   5:         if (obj == null) {
   6:             if (_array[count] == null)
   7:                 return true;
   8:         }
   9:         else if (_array[count] != null && _array[count].Equals(obj)) {
  10:             return true;
  11:         }
  12:     }
  13:     return false;
  14: }

Clear

   1: public virtual void Clear() {
   2:     Array.Clear(_array, 0, _size); // Don't need to doc this but we clear the elements so that the gc can reclaim the references.
   3:     _size = 0;
   4:     _version++;
   5: }
   6:  
   7: [MethodImplAttribute(MethodImplOptions.InternalCall)]
   8: [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
   9: public static extern void Clear(Array array, int index, int length);
  10:   

那Array.Clear调用在

Clone - 深拷贝, 直接复制数据到新的栈数组中

   1: public virtual Object Clone() {
   2:     Stack s = new Stack(_size);
   3:     s._size = _size;
   4:     Array.Copy(_array, 0, s._array, 0, _size);
   5:     s._version = _version;
   6:     return s;
   7: }

Queue:

先进先出,第一个进来的第一个出去, 查看详细(English), 中文

构造函数

   1: // Creates a queue with room for capacity objects. The default initial
   2: // capacity and grow factor are used.
   3: public Queue() 
   4:     : this(32, (float)2.0) {
   5: }
   6:  
   7: // Creates a queue with room for capacity objects. The default grow factor
   8: // is used.
   9: //
  10: public Queue(int capacity) 
  11:     : this(capacity, (float)2.0) {
  12: }
  13:  
  14: // Creates a queue with room for capacity objects. When full, the new
  15: // capacity is set to the old capacity * growFactor.
  16: //
  17: public Queue(int capacity, float growFactor) {
  18:     if (capacity < 0)
  19:         throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  20:     if (!(growFactor >= 1.0 && growFactor <= 10.0))
  21:         throw new ArgumentOutOfRangeException("growFactor", Environment.GetResourceString("ArgumentOutOfRange_QueueGrowFactor", 1, 10));
  22:  
  23:     _array = new Object[capacity];
  24:     _head = 0;
  25:     _tail = 0;
  26:     _size = 0;
  27:     _growFactor = (int)(growFactor * 100);
  28: }

和Array不太一样的是,增加了一个growfactor, 所谓growfactor,是指Array的当前索引到了容量顶峰需要增加的倍数. 比如

   1: Queue q = new Queue(10, 2);
   2: for(int i=0; i<q; i++)
   3: {
   4:     e.EnQueue(i);
   5: }
   6:  
   7: e.EnQueue(3); // The Capbility size will be 20

原理和之前Array的扩张一样,他也会在达到最大容量时,新分配一块扩大之后的大小

Enque

包含两个过程: 1. 检查容量是否达到最大是否有扩容的需要 2. 移动尾部,比较有趣的是 _tail = (_tail + 1) % _array.Length. 说明这个队列是可以循环的 :)

   1: // Adds obj to the tail of the queue.
   2: //
   3: public virtual void Enqueue(Object obj) {
   4:     if (_size == _array.Length) {
   5:         int newcapacity = (int)((long)_array.Length * (long)_growFactor / 100);
   6:         if (newcapacity < _array.Length + _MinimumGrow) {
   7:             newcapacity = _array.Length + _MinimumGrow;
   8:         }
   9:         SetCapacity(newcapacity);
  10:     }
  11:     
  12:     _array[_tail] = obj;
  13:     _tail = (_tail + 1) % _array.Length;
  14:     _size++;
  15:     _version++;
  16: }

DeQueue

设置头节点为空,等待垃圾回收时释放空间。有个问题是: 垃圾回收时这些东西会空的地方是怎么处理的,是建立一个新的队列然后把数据拷贝过去吗?等待后面的验证。。[TODO]

   1: // Removes the object at the head of the queue and returns it. If the queue
   2: // is empty, this method simply returns null.
   3: public virtual Object Dequeue() {
   4:     if (_size == 0)
   5:         throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyQueue"));
   6:     
   7:     Object removed = _array[_head];
   8:     _array[_head] = null;
   9:     _head = (_head + 1) % _array.Length;
  10:     _size--;
  11:     _version++;
  12:     return removed;
  13: }

Clear

   1: // Removes all Objects from the queue.
   2: public virtual void Clear() {
   3:     if (_head < _tail)
   4:         Array.Clear(_array, _head, _size);
   5:     else {
   6:         Array.Clear(_array, _head, _array.Length - _head);
   7:         Array.Clear(_array, 0, _tail);
   8:     }
   9:     
  10:     _head = 0;
  11:     _tail = 0;
  12:     _size = 0;
  13:     _version++;
  14: }

Clone 深拷贝

   1: public virtual Object Clone() {
   2:    Queue q = new Queue(_size);
   3:    q._size = _size;
   4:  
   5:    int numToCopy = _size;
   6:    int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
   7:    Array.Copy(_array, _head, q._array, 0, firstPart);
   8:    numToCopy -= firstPart;
   9:    if (numToCopy > 0)
  10:        Array.Copy(_array, 0, q._array, _array.Length - _head, numToCopy);
  11:  
  12:    q._version = _version;
  13:    return q;
  14: }

未完待续

写着写着觉得越写越多,到这里也算是Stack和Queue的部分结束了,下一篇接着描述List, SortedList, HashTable, Dictionary. 哇 好累啊 Orz..

posted on 2008-11-29 19:05  xwang  阅读(747)  评论(4编辑  收藏  举报

导航