Разработка на коленке

"тут должна быть красивая цитата о программировании"

Быстрая сортировка (quicksort) на OCaml

2016-08-08 18:02

Дошёл черёд до реализации быстрой сортировки на OCaml, пока я слушаю курс по алгоритмам (Algorithmic Toolbox). Поскольку основная цель - практика программирования на OCaml, то этот раз я не стал заниматься разработкой partion с ручным перемещением элементов списка, а заменил её двумя вызовами List.filter. Код для тестирования взял из сортировки слиянием, а функцию генерации тестовых данных сделал как в сортировке подсчётом, чтобы в список входили отрицательные числа.

Исходный код:

open Core.Std


let rec quicksort lst =
    let open List in
    match lst with
    | [] | [_] -> lst
    | hd :: tl ->
            let left = quicksort (filter tl (fun i -> i <= hd)) in
            let right = quicksort (filter tl (fun i -> i > hd)) in
            concat [left; [hd]; right]


let rec create_test_data = function
    | 0 -> []
    | size -> (Random.int 100) - 50 :: create_test_data (size - 1)


let render color text =
    sprintf "\027[38;5;%dm%s\027[0m\n" color text


let render_success data qs_sorted sorted =
    let color = 2 in
    let message = "Ok" in
    if List.length data < 20 then
        [
            message;
            "Data: " ^ (List.to_string data ~f:string_of_int);
            "Quicksort: " ^ (List.to_string qs_sorted ~f:string_of_int);
            "List sort: " ^ (List.to_string sorted ~f:string_of_int);
        ] |> List.map ~f:(fun str -> render color str) |> String.concat ~sep:""
    else
        render color (message ^ " size: " ^ (string_of_int (List.length data)))


let render_error data qs_sorted sorted =
    let color = 1 in
    let message = "Error"in
    [
        message;
        "Data: " ^ (List.to_string data ~f:string_of_int);
        "Quicksort: " ^ (List.to_string qs_sorted ~f:string_of_int);
        "List sort: " ^ (List.to_string sorted ~f:string_of_int);
    ] |> List.map ~f:(fun str -> render color str) |> String.concat ~sep:""



let rec test size =
    let data = create_test_data size in
    let qs_sorted = quicksort data in
    let sorted = List.sort data ~cmp:compare in
    match compare sorted qs_sorted with
    | 0 -> (
        printf "%s%!" (render_success data qs_sorted sorted);
        if size > 0 then
            test (size - 1)
    )
    | _ -> printf "%s%!" (render_error data qs_sorted sorted)


let () =
    printf "Let's begin\n";
    test 1000

Quicksort3

Ещё сделал quicksort3, где список разбивается на три части. С практической точки зрения этот код скорее бесполезен, но для тренировки разработки на OCaml подойдёт.

open Core.Std


let rec quicksort3 lst =
    let open List in
    match lst with
    | [] | [_] -> lst
    | hd :: _ ->
        match map [(<); (=); (>)] (fun f -> filter lst (fun i -> f i hd)) with
        | [l; c; r] -> concat [quicksort3 l; c; quicksort3 r]
        | _ -> assert false