| ... | ... | @@ -4,6 +4,19 @@ const math = @import("math/index.zig"); |
| 4 | 4 | |
| 5 | 5 | pub const Cmp = math.Cmp; |
| 6 | 6 | |
| 7 | /// Stable sort using O(1) space. Currently implemented as insertion sort. |
| 8 | pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { |
| 9 | {var i: usize = 1; while (i < array.len) : (i += 1) { |
| 10 | const x = array[i]; |
| 11 | var j: usize = i; |
| 12 | while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) { |
| 13 | array[j] = array[j - 1]; |
| 14 | } |
| 15 | array[j] = x; |
| 16 | }} |
| 17 | } |
| 18 | |
| 19 | /// Unstable sort using O(n) stack space. Currentl implemented as quicksort. |
| 7 | 20 | pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { |
| 8 | 21 | if (array.len > 0) { |
| 9 | 22 | quicksort(T, array, 0, array.len - 1, cmp); |
| ... | ... | @@ -58,6 +71,62 @@ fn reverse(was: Cmp) -> Cmp { |
| 58 | 71 | // --------------------------------------- |
| 59 | 72 | // tests |
| 60 | 73 | |
| 74 | test "stable sort" { |
| 75 | testStableSort(); |
| 76 | comptime testStableSort(); |
| 77 | } |
| 78 | fn testStableSort() { |
| 79 | var expected = []IdAndValue { |
| 80 | IdAndValue{.id = 0, .value = 0}, |
| 81 | IdAndValue{.id = 1, .value = 0}, |
| 82 | IdAndValue{.id = 2, .value = 0}, |
| 83 | IdAndValue{.id = 0, .value = 1}, |
| 84 | IdAndValue{.id = 1, .value = 1}, |
| 85 | IdAndValue{.id = 2, .value = 1}, |
| 86 | IdAndValue{.id = 0, .value = 2}, |
| 87 | IdAndValue{.id = 1, .value = 2}, |
| 88 | IdAndValue{.id = 2, .value = 2}, |
| 89 | }; |
| 90 | var cases = [][9]IdAndValue { |
| 91 | []IdAndValue { |
| 92 | IdAndValue{.id = 0, .value = 0}, |
| 93 | IdAndValue{.id = 0, .value = 1}, |
| 94 | IdAndValue{.id = 0, .value = 2}, |
| 95 | IdAndValue{.id = 1, .value = 0}, |
| 96 | IdAndValue{.id = 1, .value = 1}, |
| 97 | IdAndValue{.id = 1, .value = 2}, |
| 98 | IdAndValue{.id = 2, .value = 0}, |
| 99 | IdAndValue{.id = 2, .value = 1}, |
| 100 | IdAndValue{.id = 2, .value = 2}, |
| 101 | }, |
| 102 | []IdAndValue { |
| 103 | IdAndValue{.id = 0, .value = 2}, |
| 104 | IdAndValue{.id = 0, .value = 1}, |
| 105 | IdAndValue{.id = 0, .value = 0}, |
| 106 | IdAndValue{.id = 1, .value = 2}, |
| 107 | IdAndValue{.id = 1, .value = 1}, |
| 108 | IdAndValue{.id = 1, .value = 0}, |
| 109 | IdAndValue{.id = 2, .value = 2}, |
| 110 | IdAndValue{.id = 2, .value = 1}, |
| 111 | IdAndValue{.id = 2, .value = 0}, |
| 112 | }, |
| 113 | }; |
| 114 | for (cases) |*case| { |
| 115 | sort_stable(IdAndValue, (*case)[0..], cmpByValue); |
| 116 | for (*case) |item, i| { |
| 117 | assert(item.id == expected[i].id); |
| 118 | assert(item.value == expected[i].value); |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | const IdAndValue = struct { |
| 123 | id: i32, |
| 124 | value: i32, |
| 125 | }; |
| 126 | fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp { |
| 127 | return i32asc(a.value, b.value); |
| 128 | } |
| 129 | |
| 61 | 130 | test "testSort" { |
| 62 | 131 | const u8cases = [][]const []const u8 { |
| 63 | 132 | [][]const u8{"", ""}, |