数据结构-Queue队列

队列(Queue)代表了一个先进先出的对象集合。当您需要对各项进行先进先出的访问时,则使用队列。当您在列表中添加一项,称为入队,当您从列表中移除一项时,称为出队

队列是一种特殊的线性表,特殊之处在于它只允许在表头(head)进行删除操作,而在表尾(tail)进行插入操作。

队列可以分为顺序队列和循环队列,.NET中为了提高空间的利用率,采用的是循环队列

Queue<int> qu = new Queue<int>();

循环数组

循环数组不同于顺序数组,循环数组会建立两个指针,分别指向数组头部和数组尾部。

初始化时,head和last都指向数组下标空间0处,当添加元素时,为head指向的下标赋值。head后移。当再次添加时,同时head指向的下标赋值,head继续后移。

当头部元素被移除时,head指向的下标元素移除,head后移此时head指向的元素当作队首。

当last指向开辟空间的队尾时,假如队列的元素小于队列容量,则说明还有空余空间。此时last指向first开辟空间之前的空间。具体操作如下:

 当队列内元素值=队列容量值,时对其进行扩充。创建一个新的数组data,容量为原先的两倍(通常情况)将data数组中的值赋予newData。

 

 此时还需要设置建立两个指针,分别指向数组头部和数组尾部。first指向下标为0,last指向元素个数N的下标。

 

属性描述
Count获取 Queue 中包含的元素个数。
1public virtual void Clear();
从 Queue 中移除所有的元素。
2public virtual bool Contains( object obj );
判断某个元素是否在 Queue 中。
3public virtual object Dequeue();
移除并返回在 Queue 的开头的对象。
4public virtual void Enqueue( object obj );
向 Queue 的末尾添加一个对象。
5public virtual object[] ToArray();
复制 Queue 到一个新的数组中。
6public virtual void TrimToSize();
设置容量为 Queue 中元素的实际个数。

C#Queue底层实现

public class Queue : ICollection, ICloneable {
        private Object[] _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 _growFactor; // 100 == 1.0, 130 == 1.3与旧容量相乘得到新容量
        private int _version;
        [NonSerialized]
        private Object _syncRoot;
        
        private const int _MinimumGrow = 4;// 最小增长值
        private const int _ShrinkThreshold = 32;// 收缩阈值
    

构造函数

 public Queue() 
            : this(32, (float)2.0) {
        }
    
        // Creates a queue with room for capacity objects. The default grow factor
        // is used.
        //
        public Queue(int capacity) 
            : this(capacity, (float)2.0) {
        }
        
        // Creates a queue with room for capacity objects. When full, the new
        // capacity is set to the old capacity * growFactor.
        //
        public Queue(int capacity, float growFactor) {
            if (capacity < 0)
                throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
            if (!(growFactor >= 1.0 && growFactor <= 10.0))
                throw new ArgumentOutOfRangeException("growFactor", Environment.GetResourceString("ArgumentOutOfRange_QueueGrowFactor", 1, 10));
            Contract.EndContractBlock();
    
            _array = new Object[capacity];
            _head = 0;
            _tail = 0;
            _size = 0;
            _growFactor = (int)(growFactor * 100);
        }

当为默认构造函数时,Queue会自己生成一个容器大小为32,扩容因子为2.0的对象。我们可以自己设置构造函数的容量以及扩容因子growFactor(为浮点型变量)。

1、Clear()函数

 // Removes all Objects from the queue.
        public virtual 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++;
        }

Clear有两种情况:

(1)当首指针指向的下标小于尾指针指向的下标:直接从下标_head处开始移除,移除_size个元素。例子:

(2)当首指针指向的下标大于尾指针指向的下标:先清除下标_head到数组尾部的元素,再清除下标0到下标_tail的值。例子:

 2、bool Contains( object obj );

public virtual bool Contains(Object obj) {
            int index = _head;
            int count = _size;
    
            while (count-- > 0) {
                if (obj == null) {//当查询元素为空且队列头部为空时成立
                    if (_array[index] == null)
                        return true;
                } else if (_array[index] != null && _array[index].Equals(obj)) {
                    return true;
                }
                index = (index + 1) % _array.Length;
            }
    
            return false;
        }

第一个if变相的说明了队列之中能入队null。

 需要注意的是,当创建的队列的类型不为object类型时,我们无法去用Contains(null)去确定。

 null为object类型。Contains循环遍历时间复杂度O(n)。

3、object Dequeue();出队操作,移除并返回在 Queue 的开头的对象。

public virtual Object Dequeue() {
            if (Count == 0)
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EmptyQueue"));
            Contract.EndContractBlock();
    
            Object removed = _array[_head];
            _array[_head] = null;
            _head = (_head + 1) % _array.Length;
            _size--;
            _version++;
            return removed;
        }

 创建一个队列元素类型的变量,并将队首的元素赋予它。清空队首元素,_head后移(或前移)。

时间复杂度O(1).

 4、void Enqueue( object obj );向 Queue 的末尾添加一个对象。

public virtual void Enqueue(Object obj) {
            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] = obj;
            _tail = (_tail + 1) % _array.Length;
            _size++;
            _version++;
        }

(1)当队列内元素个数=容量时,创建一个新的容量大小newcapacity。此大小=队列容量*增长因子。当增长因子太小时,newcapacity<原队列容量+最小增长量时。使 newcapacity = _array.Length + _MinimumGrow;引用  SetCapacity(newcapacity)函数。

 private void SetCapacity(int capacity) {
            Object[] newarray = new Object[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++;
        }

同循环数组两种情况。时间复杂度O(1)。

(2)直接再_tail下标处添加元素,_tail向后(或向前)移动。

 5、object[] ToArray();复制 Queue 到一个新的数组中

public virtual Object[] ToArray()
        {
            Object[] arr = new Object[_size];
            if (_size==0)
                return arr;
    
            if (_head < _tail) {
                Array.Copy(_array, _head, arr, 0, _size);
            } else {
                Array.Copy(_array, _head, arr, 0, _array.Length - _head);
                Array.Copy(_array, 0, arr, _array.Length - _head, _tail);
            }
    
            return arr;
        }

同理分两种情况。

6、void TrimToSize();设置实际元素个数

 public virtual void TrimToSize()
        {
            SetCapacity(_size);
        }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值