Stack
public class Stack : IEnumerable,
System.Collections.ICollection,
IReadOnlyCollection {
private T[] _array; // Storage for stack elements
private int _size; // Number of items in the stack.
private int _version; // Used to keep enumerator in sync w/ collection.
#if !SILVERLIGHT
[NonSerialized]
#endif
private Object _syncRoot;
private const int _defaultCapacity = 4;
static T[] _emptyArray = new T[0];
///
public Stack() {
_array = _emptyArray;
_size = 0;
_version = 0;
}
// Create a stack with a specific initial capacity. The initial capacity
// must be a non-negative number.
///
public Stack(int capacity) {
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired);
_array = new T[capacity];
_size = 0;
_version = 0;
}
可以看到主要就声明了一个T类型的数组_array,_size是用来存储当前使用的栈元素个数,_version用来记录版本号(用来在foreach的时候进行判断,任何对栈的更改都会使版本号+1,如果循环中版本号有变化,会抛出异常)。_defaultCapacity为默认在第一次为栈添加元素时创建的数组大小。Stack默认的无参构造函数会将数组_array指向静态数组_emptyArray,也可以在创建Stack时指定栈数组的初始大小,这样Stack会直接创建相应大小的数组元素(这样的好处是:在已知栈大小的情况下,指定栈数组的大小,可以减少数组空间不够时,重新创建新的数组和拷贝的消耗)。
接下来,我们来看看Push()函数:
public void Push(T item) {
if (_size == _array.Length) {
T[] newArray = new T[(_array.Length == 0) ? _defaultCapacity : 2*_array.Length];
Array.Copy(_array, 0, newArray, 0, _size);
_array = newArray;
}
_array[_size++] = item;
_version++;
}
当数组填满时,如果初次创建,则创建默认大小,否则,将当前数组扩容为原来的两倍,并将原数组的内容拷贝到新数组中。接着讲值放置在数组的末尾,版本号+1。
Peek()和Pop()函数:
public T Peek() {
if (_size==0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
return _array[_size-1];
}
// Pops an item from the top of the stack. If the stack is empty, Pop
// throws an InvalidOperationException.
///
public T Pop() {
if (_size == 0)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EmptyStack);
_version++;
T item = _array[--_size];
_array[_size] = default(T); // Free memory quicker.
return item;
}
Peek和Pop的差别在于,Peek只是返回栈顶,Pop是返回栈顶元素的同时并将其删除,所以Peek实质并没有对数据进行更改,不会增加版本号,可以在foreach中使用,而Pop对数据做出了修改,会导致版本号+1。
public T[] ToArray()
{
T[] objArray = new T[_size];
int i = 0;
while(i < _size) {
objArray[i] = _array[_size-i-1];
i++;
}
return objArray;
}
很简单,就是便利所有的元素,进行到新建的数组中,唯一注意的一点是,得到的数组和Stack中的数组顺序是相反的,也就是说栈顶的元素放在了返回的数组的头部。
public bool Contains(T item) {
int count = _size;
EqualityComparer c = EqualityComparer.Default;
while (count-- > 0) {
if (((Object) item) == null) {
if (((Object) _array[count]) == null)
return true;
}
else if (_array[count] != null && c.Equals(_array[count], item) ) {
return true;
}
}
return false;
}
从这段代码我们可以看出Stack是允许插入null值的,翻回到前面的Push(),我们也可以看到,插入的时候并没有对数据做任何的约束。
下面是Stack类的所有源码:
namespace System.Collections.Generic {
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security.Permissions;
// A simple stack of objects. Internally it is implemented as an array,
// so Push can be O(n). Pop is O(1).
[DebuggerTypeProxy(typeof(System_StackDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
#if !SILVERLIGHT
[Serializable()]
#endif
[System.Runtime.InteropServices.ComVisible(false)]
public class Stack : IEnumerable,
System.Collections.ICollection,
IReadOnlyCollection {
private T[] _array; // Storage for stack elements
private int _size; // Number of items in the stack.
private int _version; // Used to keep enumerator in sync w/ collection.
#if !SILVERLIGHT
[NonSerialized]
#endif
private Object _syncRoot;
private const int _defaultCapacity = 4;
static T[] _emptyArray = new T[0];
///
public Stack() {
_array = _emptyArray;
_size = 0;
_version = 0;
}
// Create a stack with a specific initial capacity. The initial capacity
// must be a non-negative number.
///
public Stack(int capacity) {
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNumRequired);
_array = new T[capacity];
_size = 0;
_version = 0;
}
// Fills a Stack with the contents of a particular collection. The items are
// pushed onto the stack in the same order they are read by the enumerator.
//
///
public Stack(IEnumerable collection)
{
if (collection==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
ICollection c = collection as ICollection;
if( c != null) {
int count = c.Count;
_array = new T[count];
c.CopyTo(_array, 0);
_size = count;
}
else {
_size = 0;
_array = new T[_defaultCapacity];
using(IEnumerator en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Push(en.Current);
}
}
}
}
///
public int Count {
get { return _size; }
}
///
bool System.Collections.ICollection.IsSynchronized {
get { return false; }
}
///
Object System.Collections.ICollection.SyncRoot {
get {
if( _syncRoot == null) {
System.Threading.Interlocked.CompareExchange