erlang看源码——lists:sort
sort总共分了sort、split和merge三个部分,采用了归并排序的思想。
- sort只是一个入口,负责将一些较短的列表直接返回值,以及将长列表给到split开始分割列表。
- split的功能就是归并中的归,将列表分割成多个部分,然后给到merge。
- merge的功能就是归并中的并,负责将多个列表有序的合并起来,直到合并成一个列表
下面是lists.erl的部分源码(有注解稍微理一下流程哦)
sort 部分
就是一个函数的入口,加上返回一些较短队列的排序结果
-spec sort(List1) -> List2 when
List1 :: [T],
List2 :: [T],
T :: term().
%% 这里处理X<=Y的情况,先对长度为2和3,并且直接进行返回,长度大于3的数据进入到split_1
sort([X, Y | L] = L0) when X =< Y ->
case L of
[] ->
L0;
[Z] when Y =< Z ->
L0;
[Z] when X =< Z ->
[X, Z, Y];
[Z] ->
[Z, X, Y];
_ when X == Y ->
sort_1(Y, L, [X]);
_ ->
split_1(X, Y, L, [], [])
end;
%% 这里处理X>Y的情况,同样对长度2和3的数据直接进行返回,长度大于3的数据进入到split_2
sort([X, Y | L]) ->
case L of
[] ->
[Y, X];
[Z] when X =< Z ->
[Y, X | L];
[Z] when Y =< Z ->
[Y, Z, X];
[Z] ->
[Z, Y, X];
_ ->
split_2(X, Y, L, [], [])
end;
sort([_] = L) ->
L;
sort([] = L) ->
L.
%% 这里的X是之前一个循环的Y,也就是上一个循环中小的数字放进了R里,大的数字变成了这里的X,然后与未比较的列表中下一个数字进行比较
% 相等时直接继续比较下一个数字
sort_1(X, [Y | L], R) when X == Y ->
sort_1(Y, L, [X | R]);
% 下一个数字如果大于当前数字,转到split_1
sort_1(X, [Y | L], R) when X < Y ->
split_1(X, Y, L, R, []);
% 如果当前数字大于或等于下一个数字,转到split_2
sort_1(X, [Y | L], R) ->
split_2(X, Y, L, R, []);
% 如果没有下一个数字了,也就是X已经是最大,且R中是有序递减列表,就反转列表加上X后返回
sort_1(X, [], R) ->
lists:reverse(R, [X]).
split部分
分割列表每次会取到三个数XY和Z,将加入比较的前两个数XY中较小的存起来,然后将剩余的两个数按照大小给到参数继续判断,直到遇到比这两个数都小的Z的时候就保存已经按照大小排好序的这一段作为分割的一部分,然后开始分割下一段
%% Ascending.
%% X < Y
% X<Y, Y=<Z, 可以推出X<Y=<Z, 将X存进R,用YZ代替XY
split_1(X, Y, [Z | L], R, Rs) when Z >= Y ->
split_1(Y, Z, L, [X | R], Rs);
% X<Y, Y>Z, Z>=X, 可以推出X=<Z<Y, 将X存进R, 用ZY代替XY
split_1(X, Y, [Z | L], R, Rs) when Z >= X ->
split_1(Z, Y, L, [X | R], Rs);
% X<Y, Z<X, Z<Y, Z<X<Y, 如果R是空列表,直接把Z放进去, XY继续
split_1(X, Y, [Z | L], [], Rs) ->
split_1(X, Y, L, [Z], Rs);
% X<Y, Z<X, Z<Y, Z<X<Y, 暂存Z, 转到split_1_1去与未排序列表的下一个数进行比较
split_1(X, Y, [Z | L], R, Rs) ->
split_1_1(X, Y, L, R, Rs, Z);
% 未排序列表为空,循环结束,所有列表合并起来,归并排序进入并的环节
split_1(X, Y, [], R, Rs) ->
rmergel([[Y, X | R] | Rs], []).
%% 有暂存数时原来的XY与下一个数进行比较
% 同上X<Y=<Z, 将X存进R,用YZ代替XY
split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y ->
split_1_1(Y, Z, L, [X | R], Rs, S);
% 同上X=<Z<Y, 将X存进R, 用ZY代替XY
split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X ->
split_1_1(Z, Y, L, [X | R]