为了节省时间,只写一些关注的方法好了,剩下的可以MSDN嘛XD
首先是声明部分,表示为队列是一个可用于枚举的只读集合
[DebuggerTypeProxy(typeof(QueueDebugView<>))]
[DebuggerDisplay("Count = {Count}")]
public class Queue<T> : IEnumerable<T>,
System.Collections.ICollection,
IReadOnlyCollection<T>
private T[] _array;
private int _head; // First valid element in the queue
private int _tail; // Last valid element in the queue
private int _size; // Number of elements.
private int _version;
private Object _syncRoot;
private const int MinimumGrow = 4;
private const int GrowFactor = 200; // double each time
private const int DefaultCapacity = 4;
这里有“递增因子”的概念存在,因此可以从中学习到对于队列这样的数据结构,通过使用数组,如何在“满队”情况下扩充空间。
// Creates a queue with room for capacity objects. The default initial
// capacity and grow factor are used.
///
public Queue()
{
_array = Array.Empty();
}
// Creates a queue with room for capacity objects. The default grow factor
// is used.
//
///
public Queue(int capacity)
{
if (capacity < 0)
throw new ArgumentOutOfRangeException("capacity", SR.ArgumentOutOfRange_NeedNonNegNumRequired);
_array = new T[capacity];
}
// Fills a Queue with the elements of an ICollection. Uses the enumerator
// to get each of the elements.
//
///
public Queue(IEnumerable collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
_array = new T[DefaultCapacity];
using (IEnumerator en = collection.GetEnumerator())
{
while (en.MoveNext())
{
Enqueue(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
这里没什么好说的,第一个是返回当前队列内的元素数,第二个是返回同步对象。
// Removes all Objects from the queue.
///
public void Clear()
{
if (_head < _tail)
Array.Clear(_array, _head, _size);
else
{
Array.Clear(_array, _head, _array.Length - _head);
Array.Clear(_array, 0, _tail);
}
_head = 0;
_tail = 0;
_size = 0;
_version++;
}
这里可以看出来,这里的队列使用的是“循环队列”的概念(_tail入 _head 出)。这里需要再次明确的是:_size是指的元素个数而非真实的数组长度(Array.Length)
// CopyTo copies a collection into an Array, starting at a particular
// index into the array.
//
///
public void CopyTo(T[] array, int arrayIndex)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (arrayIndex < 0 || arrayIndex > array.Length)
{
throw new ArgumentOutOfRangeException("arrayIndex", SR.ArgumentOutOfRange_Index);
}
int arrayLen = array.Length;
if (arrayLen - arrayIndex < _size)
{
throw new ArgumentException(SR.Argument_InvalidOffLen);
}
int numToCopy = (arrayLen - arrayIndex < _size) ? (arrayLen - arrayIndex) : _size;
if (numToCopy == 0) return;
int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
Array.Copy(_array, _head, array, arrayIndex, firstPart);
numToCopy -= firstPart;
if (numToCopy > 0)
{
Array.Copy(_array, 0, array, arrayIndex + _array.Length - _head, numToCopy);
}
}
void System.Collections.ICollection.CopyTo(Array array, int index)
{
if (array == null)
{
throw new ArgumentNullException("array");
}
if (array.Rank != 1)
{
throw new ArgumentException(SR.Arg_RankMultiDimNotSupported);
}
if (array.GetLowerBound(0) != 0)
{
throw new ArgumentException(SR.Arg_NonZeroLowerBound);
}
int arrayLen = array.Length;
if (index < 0 || index > arrayLen)
{
throw new ArgumentOutOfRangeException("index", SR.ArgumentOutOfRange_Index);
}
if (arrayLen - index < _size)
{
throw new ArgumentException(SR.Argument_InvalidOffLen);
}
int numToCopy = (arrayLen - index < _size) ? arrayLen - index : _size;
if (numToCopy == 0) return;
try
{
int firstPart = (_array.Length - _head < numToCopy) ? _array.Length - _head : numToCopy;
Array.Copy(_array, _head, array, index, firstPart);
numToCopy -= firstPart;
if (numToCopy > 0)
{
Array.Copy(_array, 0, array, index + _array.Length - _head, numToCopy);
}
}
catch (ArrayTypeMismatchException)
{
throw new ArgumentException(SR.Argument_InvalidArrayType);
}
复制到从某一索引起的指定的一个数组中。当然中间做了一些容量是否足够等等的判断
// Adds item to the tail of the queue.
//
///
public void Enqueue(T item)
{
if (_size == _array.Length)
{
int newcapacity = (int)((long)_array.Length * (long)GrowFactor / 100);
if (newcapacity < _array.Length + MinimumGrow)
{
newcapacity = _array.Length + MinimumGrow;
}
SetCapacity(newcapacity);
}
_array[_tail] = item;
_tail = (_tail + 1) % _array.Length;
_size++;
_version++;
}
这里看一下“生长因子”的作用:就是个生长比例。。代码里跟Stack一样是两倍这样子往上加。这个强类型转换弄得整个人蒙蒙哒。
这里有个SetCapacity这个方法,这个方法的看点是如何解决从“环形队列”里抽取掉没用的数组单元。
public T Dequeue()
{
if (_size == 0)
throw new InvalidOperationException(SR.InvalidOperation_EmptyQueue);
T removed = _array[_head];
_array[_head] = default(T);
_head = (_head + 1) % _array.Length;
_size--;
_version++;
return removed;
}
这里很奇怪,退出队列时并没有检查是否空间过分冗余而作空间节省上的优化(实用阶段这一块不做是明智的吗?看来空间不值钱是趋势)
public T Peek()
{
if (_size == 0)
throw new InvalidOperationException(SR.InvalidOperation_EmptyQueue);
return _array[_head];
}
public bool Contains(T item)
{
int index = _head;
int count = _size;
EqualityComparer c = EqualityComparer.Default;
while (count-- > 0)
{
if (((Object)item) == null)
{
if (((Object)_array[index]) == null)
return true;
}
else if (_array[index] != null && c.Equals(_array[index], item))
{
return true;
}
index = (index + 1) % _array.Length;
}
return false;
}
// PRIVATE Grows or shrinks the buffer to hold capacity objects. Capacity
// must be >= _size.
private void SetCapacity(int capacity)
{
T[] newarray = new T[capacity];
if (_size > 0)
{
if (_head < _tail)
{
Array.Copy(_array, _head, newarray, 0, _size);
}
else
{
Array.Copy(_array, _head, newarray, 0, _array.Length - _head);
Array.Copy(_array, 0, newarray, _array.Length - _head, _tail);
}
}
_array = newarray;
_head = 0;
_tail = (_size == capacity) ? 0 : _size;
_version++;
}
方法是这样的:把原来在_array中的所有元素,规规矩矩排好顺序(因为是循环队列,可能下标和队内顺序不是偏序嘛)然后再把_array 指向 newarray
但是这里并没有判断capacity和size的关系!(其实Copy会报异常的)
这里特意兴冲冲的跑去VS13实验一下:会引发目标长度不够。
异常发生点:
在 System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable)
在 System.Collections.Generic.Queue`1.SetCapacity(Int32 capacity)
(看来还真的是还没开完,或者说是有新改进)
测试代码:
Queue que = new Queue<int>(1024);
for (int i = 0; i < 1023; i++)
{
que.Enqueue(i);
}
var dd = que.GetType().GetMethod("SetCapacity", BindingFlags.NonPublic | BindingFlags.Instance);
dd.Invoke(que, new Object[] { 100 });
Console.ReadKey();