Core原始碼(十一)Queue
阿新 • • 發佈:2020-07-21
Queue表示物件的先進先出集合。實現了ICollection介面,可以由陣列或連結串列兩種形式實現,在.NET中是以陣列的形式實現的。
概念
佇列是一種特殊的線性表,特殊之處在於它只允許在表頭(head)進行刪除操作,而在表尾(tail)進行插入操作。
佇列的資料元素又稱為佇列元素。在佇列中插入一個佇列元素稱為入隊,從佇列中刪除一個佇列元素成為出隊。因為佇列只允許在一段插入,在另一端刪除,所以只有最早進入佇列的元素才能最先從佇列中刪除,故佇列又稱為先進先出(FIFO—first in first out)線性表
佇列可以分為順序佇列和迴圈佇列,.NET中為了提高空間的利用率,採用的是迴圈佇列。
迴圈佇列
為充分利用向量空間,克服”假溢位”(由於入隊和出隊操作中,頭尾指標只增加不減小,致使被刪元素的空間永遠無法重新利用)現象的方法是:將向量空間想象為一個首尾相接的圓環,並稱這種向量為迴圈向量。儲存在其中的佇列稱為迴圈佇列(Circular Queue)。概念圖如下:
迴圈佇列中,由於入隊時尾指標向前追趕頭指標;出隊時頭指標向前追趕尾指標,造成空佇列和滿佇列時頭尾指標均相等。因此,無法通過條件front==rear來判別佇列是”空”還是”滿”,.NET使用一下方法判斷空佇列和滿佇列(實際.NET中,佇列的長度時自動擴容的):
(1)私有成員_size = 0時,為空佇列。
(2)_size == _array.Length時(_array為Queue內部維護的實際資料陣列),為滿佇列,這個時候會進行自動擴容(新建一個2倍於原容量的陣列)。
而出隊入隊的位置,也要用取模的方式計算,因為可能出現數組尾部到頭部的迴圈,如下
_head = (_head + 1) % _array.Length;
屬性和變數
/// <summary> /// 內部維護的陣列,實際進行資料的存放 /// </summary> private Object[] _array; /// <summary> /// First valid element in the MyQueue 表頭/// </summary> private int _head; /// <summary> /// Last valid element in the MyQueue 表尾 /// </summary> private int _tail; /// <summary> /// Number of elements. 佇列元素數量 /// </summary> private int _size; public virtual int Count { get { return _size; } } private int _growFactor; // 100 == 1.0, 130 == 1.3, 200 == 2.0 private int _version; [NonSerialized] private Object _syncRoot; private const int _MinimumGrow = 4; private const int _ShrinkThreshold = 32;
建構函式
public MyQueue(int capacity, float growFactor) { if (capacity < 0) throw new ArgumentOutOfRangeException(); if (!(growFactor >= 1.0 && growFactor <= 10.0)) throw new ArgumentOutOfRangeException(); _array = new Object[capacity]; _head = 0; _tail = 0; _size = 0; _growFactor = (int)(growFactor * 100); }
新增及擴容
入隊 // Adds obj to the tail of the MyQueue. public virtual void EnMyQueue(Object obj) { //這時候需要擴容 if (_size == _array.Length) { //使用_growFactor計算新的容量 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++; } //設定佇列的容量 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); //再複製0到尾部的資料 Array.Copy(_array, 0, newarray, _array.Length - _head, _tail); } } _array = newarray; _head = 0; //_size == capacity尾部設定為0,這樣下次新增的時候是需要擴容的 _tail = (_size == capacity) ? 0 : _size; _version++; }
出隊和清空
// Removes the object at the head of the MyQueue and returns it. If the MyQueue // is empty, this method simply returns null. public virtual Object DeMyQueue() { if (Count == 0) throw new InvalidOperationException(); //返回出隊物件 Object removed = _array[_head]; //指向設定為空 _array[_head] = null; //重新獲取新的佇列頭部位置 _head = (_head + 1) % _array.Length; _size--; _version++; return removed; } // Removes all Objects from the MyQueue. 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++; }
查詢
public virtual bool Contains(Object obj) { //從同步開始遍歷,遍歷次數為_size 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; } internal Object GetElement(int i) { return _array[(_head + i) % _array.Length]; }