在 rxswift 的框架中,在 queue.swift 檔案中使用陣列實現了乙個佇列
(先進先出fifo)。在操作次數達到 n 時,入棧和出棧的複雜度為 o(1),獲取第乙個出棧元素的複雜度也為 o(1)。
下面是根據原始碼,梳理的實現原理:
在queue
的內部使用陣列_storage
來儲存佇列中的元素,_storage 的初始容量在 queue 的初始化方法中傳入。
init(capacity: int)
複製**
隨著元素進佇列和出佇列,陣列當有元素進入佇列時,就從陣列 _storage 的索引為 0 處向後儲存。入佇列的元素儲存在陣列 _storage 中的索引,使用屬性_storage
的容量可能會改變,所以用_initialcapacity
來記錄陣列的初始化容量。
_pushnextindex
來表示。當有元素出佇列時,就從陣列 _storage 的索引為 0 處向後獲取,使用dequeueindex
屬性來表示首先要出棧的元素在陣列 _storage 中的索引。在元素入佇列和出佇列的過程中,使用屬性_count
來記錄當前棧中元素的數量。
當有元素入佇列時,如果佇列中的元素數量 _count 小於陣列 _storage 的容量_storage.count
,也就是說陣列中還有空間可以繼續儲存新的佇列元素。這時如果 _pushnextindex 小於 _storage.count,則將 _pushnextindex 不斷增加,如果 _pushnextindex 大於等於 _storage.count,則說明佇列中有的元素已經出棧,在陣列的開頭處空出了位置,則將進入佇列的索引 _pushnextindex 指向陣列的索引為 0 處,繼續向後新增元素。 所以陣列中的元素排布可能為以下兩種情況:
所以 dequeueindex 可以通過 _pushnextindex 和 _count 推導出,**如下:
private var dequeueindex: int
複製**
當有元素進入佇列時,如果佇列中的元素數量 _count 等於陣列 _storage 的容量(_storage.count)時,也就是說陣列中已經存滿了佇列的元素,這時就需要乙個更大的陣列來存放佇列元素。新的陣列的容量通過原來陣列的容量(陣列的容量大於0時)乘以係數_resizefactor
計算獲得。
// 元素進入佇列的方法
mutating func enqueue(_ element: t)
_storage[_pushnextindex] = element
_pushnextindex += 1
_count += 1
// _pushnextindex 大於 _storage.count,將 _pushnextindex 指向陣列的開頭
if _pushnextindex >= _storage.count
}複製**
怎樣對儲存佇列元素的陣列進行擴容呢?分成兩步:
建立乙個容量合適的新陣列
將原來陣列中的元素複製到新的陣列中。
建立新的陣列簡單,我們應該怎樣將原來陣列中的元素拷貝到新的陣列中。我們再次看佇列元素在陣列中的可能出現的分布情況:
可以將陣列中的元素分成兩塊,第一塊是出棧位置dequeueindex
到陣列末尾的元素,第二塊是陣列開頭到佇列的結尾的元素。
這種情況的第二塊的元素個數為0。
接下來計算兩塊的元素的數量。計算陣列容量和出棧的位置 dequeueindex 之間的間隔 spacetoendofqueue,則第一塊的元素個數為 spacetoendofqueue 和 _count 中較小的乙個,用 countelementsinfirstbatch 表示。第二塊的元素個數為元素的個數 _count 減去 countelementsinfirstbatch 的數量,用 numberofelementsinsecondbatch 表示。 接下來,只需要將第一段內的元素拷貝至新元素的開頭,將第二段拷貝至新陣列中第一段元素的末尾。
// 1.
mutating private func resizeto(_ size: int)
複製**
在元素出佇列的過程中,可能會出現陣列中的容量遠遠大於佇列中元素的數量,這時為了減少占用的記憶體空間,則需要縮小陣列的大小。所以在有元素出佇列時,需要根據條件判斷是否需要縮小陣列的大小。如果需要調整陣列容量,則申請乙個新的小容量陣列,再將元素拷貝至新的陣列中。將陣列容量調小的方法和將陣列調大的方法相同(都是通過呼叫resizeto(_)
方法)。
// 出棧
private mutating func dequeueelementonly() -> t
return _storage[index]!
}/// dequeues element or throws an exception in
case queue is empty.
////// - returns: dequeued element.
mutating func dequeue() -> t?
defer
}return dequeueelementonly()
}複製**
佇列 優先佇列的學習
佇列定義 佇列是限定只能在表尾進行 插入,在表頭進行刪除的線性表 隊尾 允許插入的一端 隊頭 允許刪除的一端 佇列的定義 include queue 標頭檔案 using namespace std 需要加上使用名稱 空間,和sort 排序函式是一樣的。queue int q 格式 queue 型別...
佇列 迴圈佇列的實現
為了可以重新利用佇列底層陣列中已刪除元素所佔的空間,消除可能出現的 假滿 現象,將順序佇列改進為迴圈佇列。迴圈佇列是首尾相連的佇列 當front rear變數達到底層陣列的capacity 1之後,再向前以為就變成0.入隊 1 判斷佇列是否已滿,已滿丟擲越界異常 2 不滿的話把元素查到隊尾,並且re...
棧的佇列(佇列)
二.關於佇列的簡單實現。順序佇列的基本實現和順序棧的實現基本相似。順序佇列在出列和入列的時候會使佇列整體向上移動,會浪費一定的空間。因此出現了一種佇列叫做迴圈佇列。迴圈佇列可以實現空間的重複利用,大大節省了空間。關於迴圈佇列的實現 建立乙個空佇列 struct node struct node in...