檢視原始碼 queue (stdlib v6.2)
FIFO 佇列的抽象資料型態。
此模組有效率地提供(雙向)FIFO 佇列。
如果引數類型錯誤,所有函式都會以 badarg
為原因失敗,例如,佇列引數不是佇列、索引不是整數,而列表引數不是列表。不正確的列表會導致內部崩潰。佇列的索引超出範圍也會導致以 badarg
為原因失敗。
某些函式(如註明)在空佇列時會以 empty
為原因失敗。
此模組使用的表示佇列的資料應被其他模組視為不透明。在抽象方面,此表示法是現有 Erlang 項的複合型別。請參閱關於資料型別的註解。任何假設瞭解格式的程式碼都處於危險的邊緣。
所有操作都具有均攤 O(1) 的執行時間,除了 all/2
、 any/2
、 delete/2
、 delete_r/2
、 delete_with/2
、 delete_with_r/2
、 filter/2
、 filtermap/2
、 fold/3
、 join/2
、 len/1
、 member/2
、 split/2
,它們具有 O(n)。為了最小化佇列的大小,減少佇列操作產生的垃圾量,佇列不包含明確的長度資訊,這就是為什麼 len/1
是 O(n)。如果這個特定操作需要更好的效能,呼叫者很容易追蹤長度。
佇列是雙向的。佇列的概念圖像是一排人(項目)等待輪到他們。佇列的前端是等待時間最長的項目所在的末端。佇列的後端是項目開始等待時進入的末端。如果改用列表的概念圖像,則前端稱為頭部,後端稱為尾部。
從前端進入,從後端退出是佇列上的反向操作。
此模組有三組介面函式:「原始 API」、「擴充 API」和「Okasaki API」。
「原始 API」和「擴充 API」都使用等待項目隊列的概念圖像。兩者都有後綴 "_r" 的反向操作。
「原始 API」的項目移除函式會傳回包含已移除項目和結果佇列的複合項。「擴充 API」包含產生較少垃圾的替代函式,以及僅用於檢查佇列末端的函式。此外,「Okasaki API」函式產生的垃圾也較少。
「Okasaki API」的靈感來自 Chris Okasaki 的「純函數資料結構」。它將佇列視為列表。這個 API 被許多人認為是奇怪且可以避免的。例如,許多反向操作都有詞彙反轉的名稱,有些具有更易讀但可能較難理解的別名。
摘要
原始 API
如果 Pred(Item)
對 Q
中的所有項目 Item
都傳回 true
,則傳回 true
,否則傳回 false
。
如果 Pred(Item)
對 Q
中至少一個項目 Item
傳回 true
,則傳回 true
,否則傳回 false
。
傳回 Q1
的副本,其中刪除第一個與 Item
匹配的項目(如果有的話)。
傳回 Q1
的副本,其中刪除最後一個與 Item
匹配的項目(如果有的話)。
傳回 Q1
的副本,其中刪除第一個使 Pred
傳回 true
的項目(如果有的話)。
傳回 Q1
的副本,其中刪除最後一個使 Pred
傳回 true
的項目(如果有的話)。
傳回一個佇列 Q2
,它是對 Q1
中的所有項目呼叫 Fun(Item)
的結果。
傳回一個佇列 Q2
,它是對 Q1
中的所有項目呼叫 Fun(Item)
的結果。
對 Queue
的連續項目 Item
呼叫 Fun(Item, AccIn)
,從 AccIn == Acc0
開始。佇列會依佇列順序遍歷,即從前端到後端。Fun/2
必須傳回新的累加器,該累加器會傳遞到下一次呼叫。該函式傳回累加器的最終值。如果佇列為空,則會傳回 Acc0
。
傳回一個包含 L
中項目的佇列,其順序相同;列表的頭部項目成為佇列的前端項目。
將 Item
插入佇列 Q1
的後端。傳回結果佇列 Q2
。
將 Item
插入佇列 Q1
的前端。傳回結果佇列 Q2
。
測試 Q
是否為空,如果是,則傳回 true
,否則傳回 false
。
測試 Term
是否為佇列,如果是,則傳回 true
,否則傳回 false
。請注意,即使不是由此模組建構的,此測試也會針對與佇列表示法一致的項傳回 true
。另請參閱關於資料型別的註解。
傳回一個佇列 Q3
,它是將 Q1
和 Q2
連接在一起的結果,其中 Q1
在 Q2
的前面。
計算並傳回佇列 Q
的長度。
如果 Item
與 Q
中的某些元素匹配,則傳回 true
,否則傳回 false
。
傳回一個空佇列。
移除佇列 Q1
前端的項目。傳回元組 {{value, Item}, Q2}
,其中 Item
是已移除的項目,Q2
是結果佇列。如果 Q1
為空,則傳回元組 {empty, Q1}
。
移除佇列 Q1
後端的項目。傳回元組 {{value, Item}, Q2}
,其中 Item
是已移除的項目,Q2
是新的佇列。如果 Q1
為空,則傳回元組 {empty, Q1}
。
傳回一個佇列 Q2
,其中包含 Q1
的項目,順序相反。
將 Q1
分成兩個。前 N
個項目會放入 Q2
,其餘項目放入 Q3
。
傳回佇列中項目的列表,其順序相同;佇列的前端項目成為列表的頭部。
擴充 API
傳回一個佇列 Q2
,它是從 Q1
中移除前端項目的結果。
傳回一個佇列 Q2
,它是從 Q1
中移除後端項目的結果。
傳回佇列 Q
前端的 Item
。
傳回佇列 Q
後端的 Item
。
傳回元組 {value, Item}
,其中 Item
是 Q
的前端項目,如果 Q
為空,則傳回 empty
。
傳回元組 {value, Item}
,其中 Item
是 Q
的後端項目,如果 Q
為空,則傳回 empty
。
Okasaki API
將 Item
插入佇列 Q1
的頭部。傳回新的佇列 Q2
。
傳回佇列 Q
的尾部項目。
從佇列 Q
的頭部傳回 Item
。
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
傳回佇列 Q
的尾部項目。
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
將 Item
作為佇列 Q1
的尾部項目插入。傳回新的佇列 Q2
。
傳回一個佇列 Q2
,它是從 Q1
中移除頭部項目的結果。
型別
原始 API
如果 Pred(Item)
對 Q
中的所有項目 Item
都傳回 true
,則傳回 true
,否則傳回 false
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
2> queue:all(fun (E) -> E > 3 end, Queue).
false
3> queue:all(fun (E) -> E > 0 end, Queue).
true
如果 Pred(Item)
對 Q
中至少一個項目 Item
傳回 true
,則傳回 true
,否則傳回 false
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
2> queue:any(fun (E) -> E > 10 end, Queue).
false
3> queue:any(fun (E) -> E > 3 end, Queue).
true
傳回 Q1
的副本,其中刪除第一個與 Item
匹配的項目(如果有的話)。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
2> Queue1 = queue:delete(3, Queue).
3> queue:member(3, Queue1).
false
傳回 Q1
的副本,其中刪除最後一個與 Item
匹配的項目(如果有的話)。
範例
1> Queue = queue:from_list([1,2,3,4,3,5]).
2> Queue1 = queue:delete_r(3, Queue).
3> queue:to_list(Queue1).
[1,2,3,4,5]
-spec delete_with(Pred, Q1) -> Q2 when Pred :: fun((Item) -> boolean()), Q1 :: queue(Item), Q2 :: queue(Item), Item :: term().
傳回 Q1
的副本,其中刪除第一個使 Pred
傳回 true
的項目(如果有的話)。
範例
1> Queue = queue:from_list([100,1,2,3,4,5]).
2> Queue1 = queue:delete_with(fun (E) -> E > 0, Queue).
3> queue:to_list(Queue1).
[1,2,3,4,5]
-spec delete_with_r(Pred, Q1) -> Q2 when Pred :: fun((Item) -> boolean()), Q1 :: queue(Item), Q2 :: queue(Item), Item :: term().
傳回 Q1
的副本,其中刪除最後一個使 Pred
傳回 true
的項目(如果有的話)。
範例
1> Queue = queue:from_list([1,2,3,4,5,100]).
2> Queue1 = queue:delete_with(fun (E) -> E > 10, Queue).
3> queue:to_list(Queue1).
[1,2,3,4,5]
-spec filter(Fun, Q1 :: queue(Item)) -> Q2 :: queue(Item) when Fun :: fun((Item) -> boolean() | [Item]).
傳回一個佇列 Q2
,它是對 Q1
中的所有項目呼叫 Fun(Item)
的結果。
如果 Fun(Item)
返回 true
,Item
會被複製到結果佇列。如果它返回 false
,Item
則不會被複製。如果它返回一個列表,列表中的元素會被插入到結果佇列中,而不是 Item
。
範例 1
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:filter(fun (E) -> E > 2 end, Queue).
{[5],[3,4]}
3> queue:to_list(Queue1).
[3,4,5]
因此,Fun(Item)
返回 [Item]
在語義上等同於返回 true
,就像返回 []
在語義上等同於返回 false
。但是返回列表會比返回原子產生更多的垃圾。
範例 2
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:filter(fun (E) -> [E, E+1] end, Queue).
{[6,5,5,4,4,3],[1,2,2,3]}
3> queue:to_list(Queue1).
[1,2,2,3,3,4,4,5,5,6]
-spec filtermap(Fun, Q1) -> Q2 when Fun :: fun((Item) -> boolean() | {true, Value}), Q1 :: queue(Item), Q2 :: queue(Item | Value), Item :: term(), Value :: term().
傳回一個佇列 Q2
,它是對 Q1
中的所有項目呼叫 Fun(Item)
的結果。
如果 Fun(Item)
返回 true
,Item
會被複製到結果佇列。如果它返回 false
,Item
則不會被複製。如果它返回 {true, NewItem}
,則此位置的佇列元素會被結果佇列中的 NewItem
取代。
範例 1
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:filtermap(fun (E) -> E > 2 end, Queue).
{[5],[3,4]}
3> queue:to_list(Queue1).
[3,4,5]
4> Queue1 = queue:filtermap(fun (E) -> {true, E+100} end, Queue).
{"ihg","ef"}
5> queue:to_list(Queue1).
"efghi
-spec fold(Fun, Acc0, Q :: queue(Item)) -> Acc1 when Fun :: fun((Item, AccIn) -> AccOut), Acc0 :: term(), Acc1 :: term(), AccIn :: term(), AccOut :: term().
對 Queue
的連續項目 Item
呼叫 Fun(Item, AccIn)
,從 AccIn == Acc0
開始。佇列會依佇列順序遍歷,即從前端到後端。Fun/2
必須傳回新的累加器,該累加器會傳遞到下一次呼叫。該函式傳回累加器的最終值。如果佇列為空,則會傳回 Acc0
。
範例
1> queue:fold(fun(X, Sum) -> X + Sum end, 0, queue:from_list([1,2,3,4,5])).
15
2> queue:fold(fun(X, Prod) -> X * Prod end, 1, queue:from_list([1,2,3,4,5])).
120
-spec from_list(L :: [Item]) -> queue(Item).
傳回一個包含 L
中項目的佇列,其順序相同;列表的頭部項目成為佇列的前端項目。
將 Item
插入佇列 Q1
的後端。傳回結果佇列 Q2
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:in(100, Queue).
{[100,5,4,3],[1,2]}
3> queue:to_list(Queue1).
[1,2,3,4,5,100]
將 Item
插入佇列 Q1
的前端。傳回結果佇列 Q2
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue1 = queue:in_r(100, Queue).
{[5,4,3],[100,1,2]}
3> queue:to_list(Queue1).
[100,1,2,3,4,5]
測試 Q
是否為空,如果是,則傳回 true
,否則傳回 false
。
測試 Term
是否為佇列,如果是,則傳回 true
,否則傳回 false
。請注意,即使不是由此模組建構的,此測試也會針對與佇列表示法一致的項傳回 true
。另請參閱關於資料型別的註解。
傳回一個佇列 Q3
,它是將 Q1
和 Q2
連接在一起的結果,其中 Q1
在 Q2
的前面。
範例
1> Queue1 = queue:from_list([1,3]).
{[3],[1]}
2> Queue2 = queue:from_list([2,4]).
{[4],[2]}
3> queue:to_list(queue:join(Queue1, Queue2)).
[1,3,2,4]
-spec len(Q :: queue()) -> non_neg_integer().
計算並傳回佇列 Q
的長度。
如果 Item
與 Q
中的某些元素匹配,則傳回 true
,否則傳回 false
。
傳回一個空佇列。
移除佇列 Q1
前端的項目。傳回元組 {{value, Item}, Q2}
,其中 Item
是已移除的項目,Q2
是結果佇列。如果 Q1
為空,則傳回元組 {empty, Q1}
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> {{value, 1=Item}, Queue1} = queue:out(Queue).
{{value,1},{[5,4,3],[2]}}
3> queue:to_list(Queue1).
[2,3,4,5]
移除佇列 Q1
後端的項目。傳回元組 {{value, Item}, Q2}
,其中 Item
是已移除的項目,Q2
是新的佇列。如果 Q1
為空,則傳回元組 {empty, Q1}
。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> {{value, 5=Item}, Queue1} = queue:out_r(Queue).
{{value,5},{[4,3],[1,2]}}
3> queue:to_list(Queue1).
[1,2,3,4]
傳回一個佇列 Q2
,其中包含 Q1
的項目,順序相反。
-spec split(N :: non_neg_integer(), Q1 :: queue(Item)) -> {Q2 :: queue(Item), Q3 :: queue(Item)}.
將 Q1
分成兩個。前 N
個項目會放入 Q2
,其餘項目放入 Q3
。
-spec to_list(Q :: queue(Item)) -> [Item].
傳回佇列中項目的列表,其順序相同;佇列的前端項目成為列表的頭部。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> List == queue:to_list(Queue).
true
擴展 API
傳回一個佇列 Q2
,它是從 Q1
中移除前端項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue = queue:drop(Queue).
{[5,4,3],[2]}
3> queue:to_list(Queue1).
[2,3,4,5]
傳回一個佇列 Q2
,它是從 Q1
中移除後端項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。
範例
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> Queue = queue:drop_r(Queue).
{[4,3],[1,2]}
3> queue:to_list(Queue1).
[1,2,3,4]
-spec get(Q :: queue(Item)) -> Item.
傳回佇列 Q
前端的 Item
。
如果 Q
為空,則會因 empty
的原因而失敗。
範例 1
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> 1 == queue:get(Queue).
true
-spec get_r(Q :: queue(Item)) -> Item.
傳回佇列 Q
後端的 Item
。
如果 Q
為空,則會因 empty
的原因而失敗。
範例 1
1> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
2> 5 == queue:get_r(Queue).
true
-spec peek(Q :: queue(Item)) -> empty | {value, Item}.
傳回元組 {value, Item}
,其中 Item
是 Q
的前端項目,如果 Q
為空,則傳回 empty
。
範例 1
1> queue:peek(queue:new()).
empty
2> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
3> queue:peek(Queue).
{value, 1}
-spec peek_r(Q :: queue(Item)) -> empty | {value, Item}.
傳回元組 {value, Item}
,其中 Item
是 Q
的後端項目,如果 Q
為空,則傳回 empty
。
範例 1
1> queue:peek_r(queue:new()).
empty
2> Queue = queue:from_list([1,2,3,4,5]).
{[5,4,3],[1,2]}
3> queue:peek_r(Queue).
{value, 5}
Okasaki API
將 Item
插入佇列 Q1
的頭部。傳回新的佇列 Q2
。
範例
1> Queue = queue:cons(0, queue:from_list([1,2,3])).
{[3,2],[0,1]}
2> queue:to_list(Queue).
[0,1,2,3]
-spec daeh(Q :: queue(Item)) -> Item.
傳回佇列 Q
的尾部項目。
如果 Q
為空,則會因 empty
的原因而失敗。
範例 1
1> queue:daeh(queue:from_list([1,2,3])).
3
-spec head(Q :: queue(Item)) -> Item.
從佇列 Q
的頭部傳回 Item
。
如果 Q
為空,則會因 empty
的原因而失敗。
範例 1
1> queue:head(queue:from_list([1,2,3])).
1
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。
範例
1> Queue = queue:init(queue:from_list([1,2,3])).
{[2],[1]}
2> queue:to_list(Queue).
[1,2]
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。
名稱 lait/1
是拼寫錯誤 - 請不要再使用它。
-spec last(Q :: queue(Item)) -> Item.
傳回佇列 Q
的尾部項目。
如果 Q
為空,則會因 empty
的原因而失敗。
範例
1> queue:last(queue:from_list([1,2,3])).
3
傳回一個佇列 Q2
,它是從 Q1
中移除尾部項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。
範例
1> Queue = queue:liat(queue:from_list([1,2,3])).
{[2],[1]}
2> queue:to_list(Queue).
[1,2]
將 Item
作為佇列 Q1
的尾部項目插入。傳回新的佇列 Q2
。
範例
1> Queue = queue:snoc(queue:from_list([1,2,3]), 4).
{[4,3,2],[1]}
2> queue:to_list(Queue).
[1,2,3,4]
傳回一個佇列 Q2
,它是從 Q1
中移除頭部項目的結果。
如果 Q1
為空,則會因 empty
的原因而失敗。