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

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

2008-11-29 19:05 387 查看

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