summaryrefslogtreecommitdiffstats
path: root/stdlib/list.ml
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/list.ml')
-rw-r--r--stdlib/list.ml98
1 files changed, 96 insertions, 2 deletions
diff --git a/stdlib/list.ml b/stdlib/list.ml
index a6aeceef5..fbdb6819c 100644
--- a/stdlib/list.ml
+++ b/stdlib/list.ml
@@ -195,6 +195,101 @@ let rec combine l1 l2 =
(** sorting *)
+let rec merge cmp l1 l2 =
+ match l1, l2 with
+ | [], l2 -> l2
+ | l1, [] -> l1
+ | h1 :: t1, h2 :: t2 ->
+ if cmp h1 h2 <= 0
+ then h1 :: merge cmp t1 l2
+ else h2 :: merge cmp l1 t2
+;;
+
+let rec chop k l =
+ if k = 0 then l else begin
+ match l with
+ | x::t -> chop (k-1) t
+ | _ -> assert false
+ end
+;;
+
+let stable_sort cmp l =
+ let rec rev_merge l1 l2 accu =
+ match l1, l2 with
+ | [], l2 -> rev_append l2 accu
+ | l1, [] -> rev_append l1 accu
+ | h1::t1, h2::t2 ->
+ if cmp h1 h2 <= 0
+ then rev_merge t1 l2 (h1::accu)
+ else rev_merge l1 t2 (h2::accu)
+ in
+ let rec rev_merge_rev l1 l2 accu =
+ match l1, l2 with
+ | [], l2 -> rev_append l2 accu
+ | l1, [] -> rev_append l1 accu
+ | h1::t1, h2::t2 ->
+ if cmp h1 h2 > 0
+ then rev_merge_rev t1 l2 (h1::accu)
+ else rev_merge_rev l1 t2 (h2::accu)
+ in
+ let rec sort n l =
+ match n, l with
+ | 2, x1 :: x2 :: _ ->
+ if cmp x1 x2 <= 0 then [x1; x2] else [x2; x1]
+ | 3, x1 :: x2 :: x3 :: _ ->
+ if cmp x1 x2 <= 0 then begin
+ if cmp x2 x3 <= 0 then [x1; x2; x3]
+ else if cmp x1 x3 <= 0 then [x1; x3; x2]
+ else [x3; x1; x2]
+ end else begin
+ if cmp x1 x3 <= 0 then [x2; x1; x3]
+ else if cmp x2 x3 <= 0 then [x2; x3; x1]
+ else [x3; x2; x1]
+ end
+ | n, l ->
+ let n1 = n asr 1 in
+ let n2 = n - n1 in
+ let l2 = chop n1 l in
+ let s1 = rev_sort n1 l in
+ let s2 = rev_sort n2 l2 in
+ rev_merge_rev s1 s2 []
+ and rev_sort n l =
+ match n, l with
+ | 2, x1 :: x2 :: _ ->
+ if cmp x1 x2 > 0 then [x1; x2] else [x2; x1]
+ | 3, x1 :: x2 :: x3 :: _ ->
+ if cmp x1 x2 > 0 then begin
+ if cmp x2 x3 > 0 then [x1; x2; x3]
+ else if cmp x1 x3 > 0 then [x1; x3; x2]
+ else [x3; x1; x2]
+ end else begin
+ if cmp x1 x3 > 0 then [x2; x1; x3]
+ else if cmp x2 x3 > 0 then [x2; x3; x1]
+ else [x3; x2; x1]
+ end
+ | n, l ->
+ let n1 = n asr 1 in
+ let n2 = n - n1 in
+ let l2 = chop n1 l in
+ let s1 = sort n1 l in
+ let s2 = sort n2 l2 in
+ rev_merge s1 s2 []
+ in
+ let len = length l in
+ if len < 2 then l else sort len l
+;;
+
+let sort = stable_sort;;
+let fast_sort = stable_sort;;
+
+(* Note: on a list of length between about 100000 (depending on the minor
+ heap size and the type of the list) and Sys.max_array_size, it is
+ actually faster to use the following, but it might also use more memory
+ because the argument list cannot be deallocated incrementally.
+
+ Also, there seems to be a bug in this code or in the
+ implementation of obj_truncate.
+
external obj_truncate : 'a array -> int -> unit = "obj_truncate"
let array_to_list_in_place a =
@@ -217,5 +312,4 @@ let stable_sort cmp l =
Array.stable_sort cmp a;
array_to_list_in_place a
;;
-
-let sort = stable_sort;;
+*)