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

为了节省时间,只写一些关注的方法好了,剩下的可以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();

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-03 09:41:30

[corefx注释说]-System.Collections.Generic.Queue<T>的相关文章

System.Collections.Generic的各容器类的用法

演示System.Collections.Generic的各容器类的用法. 包括:Dictionary,KeyValuePair,SortedDic tionary,SortedList,HashSet,SortedSet,List,Queue,Stack等 1 System.Collections.Generic.Dictionary<>; //键/值对集合 2 System.Collections.Generic.KeyValuePair<>; //键/值对结构, 作为 Dic

C#学习之System.Collections.Generic 与 System.Collections 记录

1.了解C#集合 System.Collections 命名空间 System.Collections 命名空间包含接口和类,这些接口和类定义各种对象(如列表.队列.位数组.哈希表和字典)的集合. 类   类 说明 ArrayList 使用大小可按需动态增加的数组实现 IList 接口. BitArray 管理位值的压缩数组,该值表示为布尔值,其中 true 表示位是打开的 (1),false 表示位是关闭的 (0). CaseInsensitiveComparer 比较两个对象是否相等,比较时

Resx 文件无效。未能加载 .RESX 文件中使用的类型 System.Collections.Generic.List`1请确保已在项目中添加了必需的引用。

在C#程序编写过程中,会遇到:Resx 文件无效.未能加载 .RESX 文件中使用的类型 System.Collections.Generic.List1`请确保已在项目中添加了必需的引用. 主要原因很可能是使用了类的可序列化的原因,代码如下: [Serializable] public class TimeLineItem { public string Title; public string Content; public TimeLineItem(string content) { th

vs2013c#测试using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1_CXY { class Program { stati

首先安装Unit Test Generator.方法为:工具->扩展和更新->联机->搜索“图标为装有蓝色液体的小试管.Unit Test Generator”, 编写代码,生成一个新的类,编写构造函数 与 add()函数.代码如下. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Co

webservice asmx 无法序列化接口 System.Collections.Generic.IList

转载自:http://www.cnblogs.com/chenhuzi/p/4178194.html 今天有位同事在方法里加了一个IList<entity> 的返回值,也没有测试,直接发布,导致了如下错误. NotSupportedException: 无法序列化接口 System.Collections.Generic.IList InvalidOperationException: 反射“entity”时出错. InvalidOperationException: 无法反射方法 metho

使用泛型 类型System.Collections.Generic.KeyValuePair需要2个类型参数

c#在准备使用System.Collections.Generic.KeyValuePair遍历的Hashtable时候,代码却提示有错误: 这其实是个非常简单的错误,Eclipse中通过工具弹出的提示解决方法,点下鼠标就能解决问题的,Visual Studio 2010却不行. 不过提示也说的比较清楚了,需要指定两个参数的类型. 根据你的Hashtable中保存的Key和Value的数据类型指定就可以了. 例如: KeyValuePair<string, int> KeyValuePair&

System.Collections.Generic.List&lt;T&gt; 与 System.Collections.ArrayList

[推荐] System.Collections.Generic.List<T> [原因] 泛型集合类List<T>在操作值类型的集合时可以不进行 装箱/拆箱 处理. 使得性能较 ArrayList提高了相当大的程度.因为托管堆中需要创建的对象次数减少了,所以需要应用程序执行的垃圾回收次数也相应减少.除此之外,开发人员还获得了编译时的类型安全性,源代码也因为强制类型转换的次数减少而变得更清晰.

System.Collections.Generic 源码阅读总结

ArrayList ,List ArrayList 和 List 都是不限制长度的集合类型 ,List相比ArrayList 就内部实现而言除了泛型本质没有太大区别.不过为避免装箱拆箱问题,尽可能使用List 集合内部是由数组实现,默认大小是4,但你使用无参构造函数构造实例时,内部数组大小是0,当你加入第一个元素时,才扩容为4,添加元素时,如果发现内置数组大小不够,内置数组大小会扩容为原来的两倍,每一次扩容都会重新开辟一个数组,拷贝旧数组的数据,如果你要给集合添加大量的元素却不为它初始化一个合适

关于System.Collections空间

System.Collections命名空间包含可使用的集合类和相关的接口,提供了集合的基本功能. 该命名空间下的.NET非泛型集合类如下所示: — System.Collections.ArrayList:数组集合类,使用大小可按动态增加的数组实现Ilist接口.— System.Collections.BitArray:布尔集合类,管理位值的压缩数组,该值为布尔值.— System.Collections.Queue:队列,表示对象的先进先出集合.— System.Collections.S