erlang——归并排序的lists:sort方法

本文介绍了Erlang中lists模块的sort函数,该函数基于归并排序思想,分为sort、split和merge三个步骤。sort作为入口,处理短列表;split负责分割列表;merge则将分割后的列表有序合并。文中提供了lists.erl部分源码,并详细解释了流程。
摘要由CSDN通过智能技术生成

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]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值