Skip to content

Commit bba52e7

Browse files
author
Damien Doligez
committed
changement List.sort; ajout fast_sort et List.merge
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@4884 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
1 parent db0a0a0 commit bba52e7

File tree

6 files changed

+138
-2
lines changed

6 files changed

+138
-2
lines changed

stdlib/array.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ let to_list a =
144144
if i < 0 then res else tolist (i - 1) (unsafe_get a i :: res) in
145145
tolist (length a - 1) []
146146

147+
(* Cannot use List.length here because the List module depends on Array. *)
147148
let rec list_length accu = function
148149
| [] -> accu
149150
| h::t -> list_length (succ accu) t
@@ -274,3 +275,5 @@ let stable_sort cmp a =
274275
merge l2 l1 t 0 l2 a 0;
275276
end;
276277
;;
278+
279+
let fast_sort = stable_sort;;

stdlib/array.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ val stable_sort : ('a -> 'a -> int) -> 'a array -> unit
192192
It is usually faster than the current implementation of {!Array.sort}.
193193
*)
194194

195+
val fast_sort : ('a -> 'a -> int) -> 'a array -> unit
196+
(** Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster
197+
on typical input.
198+
*)
199+
200+
195201
(**/**)
196202
(** {6 Undocumented functions} *)
197203

stdlib/arrayLabels.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ val stable_sort : cmp:('a -> 'a -> int) -> 'a array -> unit
178178
It is faster than the current implementation of {!ArrayLabels.sort}.
179179
*)
180180

181+
val fast_sort : cmp:('a -> 'a -> int) -> 'a array -> unit
182+
(** Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster
183+
on typical input.
184+
*)
185+
186+
181187
(**/**)
182188

183189
(** {6 Undocumented functions} *)

stdlib/list.ml

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,101 @@ let rec combine l1 l2 =
195195

196196
(** sorting *)
197197

198+
let rec merge cmp l1 l2 =
199+
match l1, l2 with
200+
| [], l2 -> l2
201+
| l1, [] -> l1
202+
| h1 :: t1, h2 :: t2 ->
203+
if cmp h1 h2 <= 0
204+
then h1 :: merge cmp t1 l2
205+
else h2 :: merge cmp l1 t2
206+
;;
207+
208+
let rec chop k l =
209+
if k = 0 then l else begin
210+
match l with
211+
| x::t -> chop (k-1) t
212+
| _ -> assert false
213+
end
214+
;;
215+
216+
let stable_sort cmp l =
217+
let rec rev_merge l1 l2 accu =
218+
match l1, l2 with
219+
| [], l2 -> rev_append l2 accu
220+
| l1, [] -> rev_append l1 accu
221+
| h1::t1, h2::t2 ->
222+
if cmp h1 h2 <= 0
223+
then rev_merge t1 l2 (h1::accu)
224+
else rev_merge l1 t2 (h2::accu)
225+
in
226+
let rec rev_merge_rev l1 l2 accu =
227+
match l1, l2 with
228+
| [], l2 -> rev_append l2 accu
229+
| l1, [] -> rev_append l1 accu
230+
| h1::t1, h2::t2 ->
231+
if cmp h1 h2 > 0
232+
then rev_merge_rev t1 l2 (h1::accu)
233+
else rev_merge_rev l1 t2 (h2::accu)
234+
in
235+
let rec sort n l =
236+
match n, l with
237+
| 2, x1 :: x2 :: _ ->
238+
if cmp x1 x2 <= 0 then [x1; x2] else [x2; x1]
239+
| 3, x1 :: x2 :: x3 :: _ ->
240+
if cmp x1 x2 <= 0 then begin
241+
if cmp x2 x3 <= 0 then [x1; x2; x3]
242+
else if cmp x1 x3 <= 0 then [x1; x3; x2]
243+
else [x3; x1; x2]
244+
end else begin
245+
if cmp x1 x3 <= 0 then [x2; x1; x3]
246+
else if cmp x2 x3 <= 0 then [x2; x3; x1]
247+
else [x3; x2; x1]
248+
end
249+
| n, l ->
250+
let n1 = n asr 1 in
251+
let n2 = n - n1 in
252+
let l2 = chop n1 l in
253+
let s1 = rev_sort n1 l in
254+
let s2 = rev_sort n2 l2 in
255+
rev_merge_rev s1 s2 []
256+
and rev_sort n l =
257+
match n, l with
258+
| 2, x1 :: x2 :: _ ->
259+
if cmp x1 x2 > 0 then [x1; x2] else [x2; x1]
260+
| 3, x1 :: x2 :: x3 :: _ ->
261+
if cmp x1 x2 > 0 then begin
262+
if cmp x2 x3 > 0 then [x1; x2; x3]
263+
else if cmp x1 x3 > 0 then [x1; x3; x2]
264+
else [x3; x1; x2]
265+
end else begin
266+
if cmp x1 x3 > 0 then [x2; x1; x3]
267+
else if cmp x2 x3 > 0 then [x2; x3; x1]
268+
else [x3; x2; x1]
269+
end
270+
| n, l ->
271+
let n1 = n asr 1 in
272+
let n2 = n - n1 in
273+
let l2 = chop n1 l in
274+
let s1 = sort n1 l in
275+
let s2 = sort n2 l2 in
276+
rev_merge s1 s2 []
277+
in
278+
let len = length l in
279+
if len < 2 then l else sort len l
280+
;;
281+
282+
let sort = stable_sort;;
283+
let fast_sort = stable_sort;;
284+
285+
(* Note: on a list of length between about 100000 (depending on the minor
286+
heap size and the type of the list) and Sys.max_array_size, it is
287+
actually faster to use the following, but it might also use more memory
288+
because the argument list cannot be deallocated incrementally.
289+
290+
Also, there seems to be a bug in this code or in the
291+
implementation of obj_truncate.
292+
198293
external obj_truncate : 'a array -> int -> unit = "obj_truncate"
199294
200295
let array_to_list_in_place a =
@@ -217,5 +312,4 @@ let stable_sort cmp l =
217312
Array.stable_sort cmp a;
218313
array_to_list_in_place a
219314
;;
220-
221-
let sort = stable_sort;;
315+
*)

stdlib/list.mli

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,3 +260,17 @@ val stable_sort : ('a -> 'a -> int) -> 'a list -> 'a list
260260
The current implementation uses Merge Sort. It runs in constant
261261
heap space and logarithmic stack space.
262262
*)
263+
264+
val fast_sort : ('a -> 'a -> int) -> 'a list -> 'a list
265+
(** Same as {!List.sort} or {!List.stable_sort}, whichever is faster
266+
on typical input. *)
267+
268+
val merge : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
269+
(** Merge two lists:
270+
Assuming that [l1] and [l2] are sorted according to the
271+
comparison function [cmp], [merge cmp l1 l2] will return a
272+
sorted list containting all the elements of [l1] and [l2].
273+
If several elements compare equal, the elements of [l1] will be
274+
before the elements of [l2].
275+
Not tail-recursive (sum of the lenghts of the arguments).
276+
*)

stdlib/listLabels.mli

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,16 @@ val stable_sort : cmp:('a -> 'a -> int) -> 'a list -> 'a list
268268
heap space and logarithmic stack space.
269269
*)
270270

271+
val fast_sort : cmp:('a -> 'a -> int) -> 'a list -> 'a list
272+
(** Same as {!List.sort} or {!List.stable_sort}, whichever is faster
273+
on typical input. *)
274+
275+
val merge : cmp:('a -> 'a -> int) -> 'a list -> 'a list -> 'a list
276+
(** Merge two lists:
277+
Assuming that [l1] and [l2] are sorted according to the
278+
comparison function [cmp], [merge cmp l1 l2] will return a
279+
sorted list containting all the elements of [l1] and [l2].
280+
If several elements compare equal, the elements of [l1] will be
281+
before the elements of [l2].
282+
Not tail-recursive (sum of the lenghts of the arguments).
283+
*)

0 commit comments

Comments
 (0)