From 4c76bfdc1f460692d378803b478f02dc45b7e049 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 30 Jun 2011 19:09:30 -0700 Subject: [PATCH] stdlib: Add an interior vector version of sort and a test case --- src/lib/sort.rs | 136 +++++++++++++++++++++++++++++ src/test/run-pass/lib-sort-ivec.rs | 28 ++++++ 2 files changed, 164 insertions(+) create mode 100644 src/test/run-pass/lib-sort-ivec.rs diff --git a/src/lib/sort.rs b/src/lib/sort.rs index 445f1bf70f8..4845c9ed25a 100644 --- a/src/lib/sort.rs +++ b/src/lib/sort.rs @@ -1,6 +1,9 @@ import vec::len; import vec::slice; +import ilen = ivec::len; +import islice = ivec::slice; +export ivector; export lteq; export merge_sort; export quick_sort; @@ -130,6 +133,139 @@ fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq, qsort3[T](compare_func_lt, compare_func_eq, arr, 0, (vec::len[T](arr) as int) - 1); } + +mod ivector { + export merge_sort; + export quick_sort; + export quick_sort3; + + type lteq[T] = fn(&T, &T) -> bool; + + fn merge_sort[T](lteq[T] le, &T[] v) -> T[] { + fn merge[T](lteq[T] le, &T[] a, &T[] b) -> T[] { + let T[] rs = ~[]; + let uint a_len = ilen[T](a); + let uint a_ix = 0u; + let uint b_len = ilen[T](b); + let uint b_ix = 0u; + while (a_ix < a_len && b_ix < b_len) { + if (le(a.(a_ix), b.(b_ix))) { + rs += ~[a.(a_ix)]; + a_ix += 1u; + } else { rs += ~[b.(b_ix)]; b_ix += 1u; } + } + rs += islice[T](a, a_ix, a_len); + rs += islice[T](b, b_ix, b_len); + ret rs; + } + let uint v_len = ilen[T](v); + if (v_len <= 1u) { ret v; } + let uint mid = v_len / 2u; + let T[] a = islice[T](v, 0u, mid); + let T[] b = islice[T](v, mid, v_len); + ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b)); + } + + fn swap[T](&T[mutable] arr, uint x, uint y) { + auto a = arr.(x); + arr.(x) = arr.(y); + arr.(y) = a; + } + + fn part[T](lteq[T] compare_func, &T[mutable] arr, uint left, uint right, + uint pivot) -> uint { + auto pivot_value = arr.(pivot); + swap[T](arr, pivot, right); + let uint storage_index = left; + let uint i = left; + while (i < right) { + if (compare_func({ arr.(i) }, pivot_value)) { + swap[T](arr, i, storage_index); + storage_index += 1u; + } + i += 1u; + } + swap[T](arr, storage_index, right); + ret storage_index; + } + + fn qsort[T](lteq[T] compare_func, &T[mutable] arr, uint left, + uint right) { + if (right > left) { + auto pivot = (left + right) / 2u; + auto new_pivot = part[T](compare_func, arr, left, right, pivot); + if (new_pivot == 0u) { ret; } + qsort[T](compare_func, arr, left, new_pivot - 1u); + qsort[T](compare_func, arr, new_pivot + 1u, right); + } + } + + fn quick_sort[T](lteq[T] compare_func, &T[mutable] arr) { + if (ilen[T](arr) == 0u) { ret; } + qsort[T](compare_func, arr, 0u, ilen[T](arr) - 1u); + } + + + // Based on algorithm presented by Sedgewick and Bentley here: + // http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf + // According to these slides this is the algorithm of choice for + // 'randomly ordered keys, abstract compare' & 'small number of key values' + fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq, + &T[mutable] arr, int left, int right) { + if (right <= left) { ret; } + let T v = arr.(right); + let int i = left - 1; + let int j = right; + let int p = i; + let int q = j; + while (true) { + i += 1; + while (compare_func_lt({ arr.(i) }, v)) { i += 1; } + j -= 1; + while (compare_func_lt(v, { arr.(j) })) { + if (j == left) { break; } + j -= 1; + } + if (i >= j) { break; } + swap[T](arr, i as uint, j as uint); + if (compare_func_eq({ arr.(i) }, v)) { + p += 1; + swap[T](arr, p as uint, i as uint); + } + if (compare_func_eq(v, { arr.(j) })) { + q -= 1; + swap[T](arr, j as uint, q as uint); + } + } + swap[T](arr, i as uint, right as uint); + j = i - 1; + i += 1; + let int k = left; + while (k < p) { + swap[T](arr, k as uint, j as uint); + k += 1; + j -= 1; + if (k == ilen[T](arr) as int) { break; } + } + k = right - 1; + while (k > q) { + swap[T](arr, i as uint, k as uint); + k -= 1; + i += 1; + if (k == 0) { break; } + } + qsort3[T](compare_func_lt, compare_func_eq, arr, left, j); + qsort3[T](compare_func_lt, compare_func_eq, arr, i, right); + } + + fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq, + &T[mutable] arr) { + if (ilen[T](arr) == 0u) { ret; } + qsort3[T](compare_func_lt, compare_func_eq, arr, 0, + (ilen[T](arr) as int) - 1); + } +} + // Local Variables: // mode: rust; // fill-column: 78; diff --git a/src/test/run-pass/lib-sort-ivec.rs b/src/test/run-pass/lib-sort-ivec.rs new file mode 100644 index 00000000000..6b957c8a4ab --- /dev/null +++ b/src/test/run-pass/lib-sort-ivec.rs @@ -0,0 +1,28 @@ +// xfail-stage0 + +use std; + +fn check_sort(&int[] v1, &int[] v2) { + auto len = std::ivec::len[int](v1); + fn lteq(&int a, &int b) -> bool { ret a <= b; } + auto f = lteq; + auto v3 = std::sort::ivector::merge_sort[int](f, v1); + auto i = 0u; + while (i < len) { log v3.(i); assert (v3.(i) == v2.(i)); i += 1u; } +} + +fn main() { + { + auto v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + auto v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { auto v1 = ~[1, 1, 1]; auto v2 = ~[1, 1, 1]; check_sort(v1, v2); } + { let int[] v1 = ~[]; let int[] v2 = ~[]; check_sort(v1, v2); } + { auto v1 = ~[9]; auto v2 = ~[9]; check_sort(v1, v2); } + { + auto v1 = ~[9, 3, 3, 3, 9]; + auto v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } +}