[corefx注释说]-System.Collections.Generic.Queue<T>

来源:互联网 发布:网络主持人特点 编辑:程序博客网 时间:2024/06/01 10:22

为了节省时间,只写一些关注的方法好了,剩下的可以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.        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue"]/*' />        public Queue()        {            _array = Array.Empty<T>();        }        // Creates a queue with room for capacity objects. The default grow factor        // is used.        //        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue1"]/*' />        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.        //        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Queue3"]/*' />        public Queue(IEnumerable<T> collection)        {            if (collection == null)                throw new ArgumentNullException("collection");            _array = new T[DefaultCapacity];            using (IEnumerator<T> en = collection.GetEnumerator())            {                while (en.MoveNext())                {                    Enqueue(en.Current);                }            }        }

提供三种构造方法:

  1. 构造空队列
  2. 构造指定空间容量的队列
  3. 复制已有队列(特别注意这个,很有意思)

属性

        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Count"]/*' />        public int Count        {            get { return _size; }        }        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.IsSynchronized"]/*' />        bool System.Collections.ICollection.IsSynchronized        {            get { return false; }        }        Object System.Collections.ICollection.SyncRoot        {            get            {                if (_syncRoot == null)                {                    System.Threading.Interlocked.CompareExchange<Object>(ref _syncRoot, new Object(), null);                }                return _syncRoot;            }        }

这里没什么好说的,第一个是返回当前队列内的元素数,第二个是返回同步对象。

方法

void Clear() //清除队列内所有元素

       // Removes all Objects from the queue.        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Clear"]/*' />        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)

void CopyTo(T[], int) / void Copy(Array, int) 复制到某一数组中

        // CopyTo copies a collection into an Array, starting at a particular        // index into the array.        //         /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.CopyTo"]/*' />        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);            }

复制到从某一索引起的指定的一个数组中。当然中间做了一些容量是否足够等等的判断

void Enqueue(T) 入队列
        // Adds item to the tail of the queue.        //        /// <include file='doc\Queue.uex' path='docs/doc[@for="Queue.Enqueue"]/*' />        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这个方法,这个方法的看点是如何解决从“环形队列”里抽取掉没用的数组单元。

T Dequeue() //出队列

        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;        }

这里很奇怪,退出队列时并没有检查是否空间过分冗余而作空间节省上的优化(实用阶段这一块不做是明智的吗?看来空间不值钱是趋势)

T Peek() //队尾元素

        public T Peek()        {            if (_size == 0)                throw new InvalidOperationException(SR.InvalidOperation_EmptyQueue);            return _array[_head];        }

bool Contains(T) 集合中是否存在某元素

        public bool Contains(T item)        {            int index = _head;            int count = _size;            EqualityComparer<T> c = EqualityComparer<T>.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;        }

void SetCapacity(int) 设置队列容量

        // 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<Int32> 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();
0 0
原创粉丝点击