基本数据结构解析之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..