queue.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 278 行
ERL
278 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(queue).%% New module interface-export([is_empty/1,len/1, cons/2,head/1,tail/1,snoc/2,last/1,daeh/1,init/1,lait/1, reverse/1,join/2,split/2]).%% New "old style" module interface-export([in_r/2,out_r/1,from_list/1]).%%--------------------------------------------------------------------------%% The original module interface-export([new/0, in/2, out/1, to_list/1]).%% efficient implementation of fifo queuesnew() -> {[],[]}.%% Append to tailin(X, {R,F}=Q) when is_list(R), is_list(F) -> snoc(Q, X);in(X, Q) -> erlang:fault(badarg, [X,Q]).%% Take from headout({In,[V]}) when is_list(In) -> {{value,V},r2f(In)};out({In,[V|Out]}) when is_list(In) -> {{value,V},{In,Out}};out({[],[]}=Q) -> {empty,Q};out({[V],[]}) -> {{value,V},{[],[]}};out({[_|_]=In,[]}) -> out(r2f(In));out(Q) -> erlang:fault(badarg, [Q]).to_list({In,Out}) when is_list(In), is_list(Out) -> Out++lists:reverse(In, []);to_list(Q) -> erlang:fault(badarg, [Q]).%%--------------------------------------------------------------------------%% Some new "old style" functions for reversed queue handling.%% Prepend to headin_r(X, {R,F}=Q) when is_list(R), is_list(F) -> cons(X, Q);in_r(X, Q) -> erlang:fault(badarg, [X,Q]).%% Take from tailout_r({[V],Out}) when is_list(Out) -> {{value,V},f2r(Out)};out_r({[V|In],Out}) when is_list(Out) -> {{value,V},{In,Out}};out_r({[],[]}=Q) -> {empty,Q};out_r({[],[V]}) -> {{value,V},{[],[]}};out_r({[],[_|_]=Out}) -> out_r(f2r(Out));out_r(Q) -> erlang:fault(badarg, [Q]).%% Create queue from listfrom_list(L) when is_list(L) -> {[],L};from_list(L) -> erlang:fault(badarg, [L]).%%--------------------------------------------------------------------------%% New API inspired by an Erlang user contribution "deque.erl" %% by Claes Wikstrom <klacke@kaja.klacke.net> 1999.%%%% This implementation does not use the internal data format from Klacke's%% doubly ended queues that was "shamelessly stolen" from %% "Purely Functional Data structures" by Chris Okasaki, since the data%% format of this module must remain the same in case some application%% has saved a queue in external format or sends it to an old node.%%%% This implementation tries to do the best of the situation and should %% be almost as efficient as Okasaki's queues, except for len/1 that%% is O(n) in this implementation instead of O(1).%%%% The implementation does this by trying to keep least at least one %% element in both the forward and the reversed lists so that %% i.e head/1 or last/1 will not have to reverse a list%% to find the element.%%%% To be compatible with the old version of this module, as much data as %% possible is moved to the receiving side using lists:reverse/2 when data%% is needed, except for two elements (when possible). These two elements%% are kept to prevent alternating tail/1 and init/1 operations from %% moving data back and forth between the sides.%%%% An alternative would be to balance for equal list length when one side%% is exhausted. Although this could be better for a general double%% ended queue, it would more han double the amortized cost for %% the normal case (one way queue).is_empty({[],[]}) -> true;is_empty({In,Out}) when is_list(In), is_list(Out) -> false;is_empty(Q) -> erlang:fault(badarg, [Q]).len({In,Out}) when is_list(In), is_list(Out) -> erlang:length(In)+erlang:length(Out);len(Q) -> erlang:fault(badarg, [Q]).%% Cons to head%%%% Put at least one element in each list, if it is cheapcons(X, {[],[]}) -> {[], [X]};cons(X, {[], [_]=F}) -> {F,[X]};cons(X, {R,F}) when is_list(R), is_list(F) -> {R,[X|F]};cons(X, Q) -> erlang:fault(badarg, [X,Q]).%% Return head elementhead({R,[H|_]}) when is_list(R) -> H;head({[],[]}=Q) -> erlang:fault(empty, [Q]);head({[H],[]}) -> H;head({[_|R],[]}) -> [H|_] = lists:reverse(R), H;head(Q) -> erlang:fault(badarg, [Q]).%% Remove head element and return resulting queuetail({R, [_]}) when is_list(R) -> r2f(R);tail({R, [_|F]}) when is_list(R) -> {R,F};tail({[],[]}=Q) -> erlang:fault(empty, [Q]);tail({[_],[]}) -> {[],[]};tail({[_|_]=R,[]}) -> tail(r2f(R));tail(Q) -> erlang:fault(badarg, [Q]).%% Functions operating on the other end of the queue%% Cons to tail%%%% Put at least one element in each list, if it is cheapsnoc({[],[]}, X) -> {[X], []};snoc({[_]=R, []}, X) -> {[X], R};snoc({R,F}, X) when is_list(R), is_list(F) -> {[X|R],F};snoc(Q, X) -> erlang:fault(badarg, [Q,X]).%% Return last elementdaeh(Q) -> last(Q).last({[H|_],F}) when is_list(F) -> H;last({[],[]}=Q) -> erlang:fault(empty, [Q]);last({[],[H]}) -> H;last({[],[_|R]}) -> [H|_] = lists:reverse(R), H;last(Q) -> erlang:fault(badarg, [Q]).%% Remove tail element and return resulting queuelait(Q) -> init(Q).init({[_], F}) when is_list(F) -> f2r(F);init({[_|R], F}) when is_list(F) -> {R,F};init({[],[]}=Q) -> erlang:fault(empty, [Q]);init({[],[_]}) -> {[],[]};init({[],[_|_]=F}) -> init(f2r(F));init(Q) -> erlang:fault(badarg, [Q]).%% Return reversed queuereverse({R,F}) when is_list(R), is_list(F) -> {F,R};reverse(Q) -> erlang:fault(badarg, [Q]).%% Join two queues (perhaps not very efficient)join({R,F}=Q, {[],[]}) when is_list(R), is_list(F) -> Q;join({[],[]}, {R,F}=Q) when is_list(R), is_list(F) -> Q;join({R1,F1}, {R2,F2}) when is_list(R1), is_list(F1), is_list(R2), is_list(F2) -> {R2,F1++lists:reverse(R1,F2)};join(Q1, Q2) -> erlang:fault(badarg, [Q1,Q2]).%% Split a queue in two (perhaps not very efficient)split(N, {R,F}=Q) when N =:= 0, is_list(R), is_list(F) -> {{[],[]},Q};split(N, {R,F}=Q) when is_integer(N), N > 0, is_list(R), is_list(F) -> Lf = erlang:length(F), if N < Lf -> {F1,F2} = lists:split(N, F), {f2r(F1),{R,F2}}; N > Lf -> case catch lists:split(erlang:length(R)-(N-Lf), R) of {'EXIT',_} -> erlang:fault(badarg, [N,Q]); {R1,R2} -> {{R2,F},r2f(R1)} end; true -> {f2r(F),r2f(R)} end;split(N, Q) -> erlang:fault(badarg, [N,Q]).%%--------------------------------------------------------------------------%% Internal workers%% Move all but two from R to F, if there are enoughr2f([]) -> {[],[]};r2f([_]=R) -> {[],R};r2f([H1,H2]) -> {[H1],[H2]};r2f([H1,H2|T]) -> {[H1,H2],lists:reverse(T, [])}.%% Move all but two from F to R, if there are enoughf2r([]) -> {[],[]};f2r([_]=F) -> {F,[]};f2r([H1,H2]) -> {[H2],[H1]};f2r([H1,H2|T]) -> {lists:reverse(T, []),[H1,H2]}.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?