OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// Tests algorithm utilities. |
| 6 |
| 7 import "package:collection_helpers/all.dart"; |
| 8 import "package:unittest/unittest.dart"; |
| 9 import 'dart:math'; |
| 10 |
| 11 void main() { |
| 12 void testShuffle(List list) { |
| 13 List copy = list.toList(); |
| 14 shuffle(list); |
| 15 expect(new UnorderedIterableEquality().equals(list, copy), isTrue); |
| 16 } |
| 17 |
| 18 test("Shuffle 0", () { |
| 19 testShuffle([]); |
| 20 }); |
| 21 test("Shuffle 1", () { |
| 22 testShuffle([1]); |
| 23 }); |
| 24 test("Shuffle 3", () { |
| 25 testShuffle([1, 2, 3]); |
| 26 }); |
| 27 test("Shuffle 10", () { |
| 28 testShuffle([1, 2, 3, 4, 5, 1, 3, 5, 7, 9]); |
| 29 }); |
| 30 test("Shuffle shuffles", () { |
| 31 List l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
| 32 List c = l.toList(); |
| 33 int count = 0; |
| 34 do { |
| 35 shuffle(l); |
| 36 if (!const ListEquality().equals(c, l)) return; |
| 37 // Odds of not changing the order should be one in ~ 16! ~= 2e+13. |
| 38 // Repeat this 10 times, and the odds of accidentally shuffling to the |
| 39 // same result every time is disappearingly tiny. |
| 40 count++; |
| 41 // If this happens even once, it's ok to report it. |
| 42 print("Failed shuffle $count times"); |
| 43 if (count == 10) fail("Shuffle didn't change order."); |
| 44 } while (true); |
| 45 }); |
| 46 test("Shuffle sublist", (){ |
| 47 List l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; |
| 48 List c = l.toList(); |
| 49 shuffle(l, 4, 12); |
| 50 expect(const IterableEquality().equals(l.getRange(0, 4), |
| 51 c.getRange(0, 4)), isTrue); |
| 52 expect(const IterableEquality().equals(l.getRange(12, 16), |
| 53 c.getRange(12, 16)), isTrue); |
| 54 expect(const UnorderedIterableEquality().equals(l.getRange(4, 12), |
| 55 c.getRange(4, 12)), |
| 56 isTrue); |
| 57 |
| 58 }); |
| 59 |
| 60 test("binsearch0", () { |
| 61 expect(binarySearch([], 2), equals(-1)); |
| 62 expect(binarySearch([], 2, location:true), equals(0)); |
| 63 }); |
| 64 |
| 65 test("binsearch1", () { |
| 66 expect(binarySearch([5], 2), equals(-1)); |
| 67 expect(binarySearch([5], 5), equals(0)); |
| 68 expect(binarySearch([5], 7), equals(-1)); |
| 69 expect(binarySearch([5], 2, location:true), equals(0)); |
| 70 expect(binarySearch([5], 5, location:true), equals(0)); |
| 71 expect(binarySearch([5], 7, location:true), equals(1)); |
| 72 }); |
| 73 |
| 74 test("binsearch3", () { |
| 75 expect(binarySearch([0, 5, 10], -1), equals(-1)); |
| 76 expect(binarySearch([0, 5, 10], 0), equals(0)); |
| 77 expect(binarySearch([0, 5, 10], 2), equals(-1)); |
| 78 expect(binarySearch([0, 5, 10], 5), equals(1)); |
| 79 expect(binarySearch([0, 5, 10], 7), equals(-1)); |
| 80 expect(binarySearch([0, 5, 10], 10), equals(2)); |
| 81 expect(binarySearch([0, 5, 10], 12), equals(-1)); |
| 82 expect(binarySearch([0, 5, 10], -1, location: true), equals(0)); |
| 83 expect(binarySearch([0, 5, 10], 0, location:true), equals(0)); |
| 84 expect(binarySearch([0, 5, 10], 2, location:true), equals(1)); |
| 85 expect(binarySearch([0, 5, 10], 5, location:true), equals(1)); |
| 86 expect(binarySearch([0, 5, 10], 7, location:true), equals(2)); |
| 87 expect(binarySearch([0, 5, 10], 10, location:true), equals(2)); |
| 88 expect(binarySearch([0, 5, 10], 12, location:true), equals(3)); |
| 89 }); |
| 90 |
| 91 test("binsearchCompare0", () { |
| 92 expect(binarySearch([], new C(2), compare: compareC), equals(-1)); |
| 93 expect(binarySearch([], new C(2), location:true, compare: compareC), |
| 94 equals(0)); |
| 95 }); |
| 96 |
| 97 test("binsearchCompare1", () { |
| 98 var l1 = [new C(5)]; |
| 99 expect(binarySearch(l1, new C(2), compare: compareC), equals(-1)); |
| 100 expect(binarySearch(l1, new C(5), compare: compareC), equals(0)); |
| 101 expect(binarySearch(l1, new C(7), compare: compareC), equals(-1)); |
| 102 expect(binarySearch(l1, new C(2), location:true, compare: compareC), |
| 103 equals(0)); |
| 104 expect(binarySearch(l1, new C(5), location:true, compare: compareC), |
| 105 equals(0)); |
| 106 expect(binarySearch(l1, new C(7), location:true, compare: compareC), |
| 107 equals(1)); |
| 108 }); |
| 109 |
| 110 test("binsearchCompare3", () { |
| 111 var l3 = [new C(0), new C(5), new C(10)]; |
| 112 expect(binarySearch(l3, new C(-1), compare: compareC), equals(-1)); |
| 113 expect(binarySearch(l3, new C(0), compare: compareC), equals(0)); |
| 114 expect(binarySearch(l3, new C(2), compare: compareC), equals(-1)); |
| 115 expect(binarySearch(l3, new C(5), compare: compareC), equals(1)); |
| 116 expect(binarySearch(l3, new C(7), compare: compareC), equals(-1)); |
| 117 expect(binarySearch(l3, new C(10), compare: compareC), equals(2)); |
| 118 expect(binarySearch(l3, new C(12), compare: compareC), equals(-1)); |
| 119 expect(binarySearch(l3, new C(-1), location: true, compare: compareC), |
| 120 equals(0)); |
| 121 expect(binarySearch(l3, new C(0), location:true, compare: compareC), |
| 122 equals(0)); |
| 123 expect(binarySearch(l3, new C(2), location:true, compare: compareC), |
| 124 equals(1)); |
| 125 expect(binarySearch(l3, new C(5), location:true, compare: compareC), |
| 126 equals(1)); |
| 127 expect(binarySearch(l3, new C(7), location:true, compare: compareC), |
| 128 equals(2)); |
| 129 expect(binarySearch(l3, new C(10), location:true, compare: compareC), |
| 130 equals(2)); |
| 131 expect(binarySearch(l3, new C(12), location:true, compare: compareC), |
| 132 equals(3)); }); |
| 133 |
| 134 test("insertionSortRandom", () { |
| 135 Random random = new Random(); |
| 136 for (int i = 0; i < 25; i++) { |
| 137 List list = new List(i); |
| 138 for (int j = 0; j < i; j++) { |
| 139 list[j] = random.nextInt(25); // Expect some equal elements. |
| 140 } |
| 141 insertionSort(list); |
| 142 for (int j = 1; j < i; j++) { |
| 143 expect(list[j - 1], lessThanOrEqualTo(list[j])); |
| 144 } |
| 145 } |
| 146 }); |
| 147 |
| 148 test("insertionSortSubRanges", () { |
| 149 List l = [6, 5, 4, 3, 2, 1]; |
| 150 insertionSort(l, start: 2, end: 4); |
| 151 expect(l, equals([6, 5, 3, 4, 2, 1])); |
| 152 insertionSort(l, start: 1, end: 1); |
| 153 expect(l, equals([6, 5, 3, 4, 2, 1])); |
| 154 insertionSort(l, start: 4, end: 6); |
| 155 expect(l, equals([6, 5, 3, 4, 1, 2])); |
| 156 insertionSort(l, start: 0, end: 2); |
| 157 expect(l, equals([5, 6, 3, 4, 1, 2])); |
| 158 insertionSort(l, start: 0, end: 6); |
| 159 expect(l, equals([1, 2, 3, 4, 5, 6])); |
| 160 }); |
| 161 |
| 162 test("insertionSortSpecialCases", () { |
| 163 List l = [6, 6, 6, 6, 6, 6]; |
| 164 insertionSort(l); |
| 165 expect(l, equals([6, 6, 6, 6, 6, 6])); |
| 166 |
| 167 l = [6, 6, 3, 3, 0, 0]; |
| 168 insertionSort(l); |
| 169 expect(l, equals([0, 0, 3, 3, 6, 6])); |
| 170 }); |
| 171 |
| 172 test("MergeSortRandom", () { |
| 173 Random random = new Random(); |
| 174 for (int i = 0; i < 250; i += 1) { |
| 175 List list = new List(i); |
| 176 for (int j = 0; j < i; j++) { |
| 177 list[j] = random.nextInt(i); // Expect some equal elements. |
| 178 } |
| 179 mergeSort(list); |
| 180 for (int j = 1; j < i; j++) { |
| 181 expect(list[j - 1], lessThanOrEqualTo(list[j])); |
| 182 } |
| 183 } |
| 184 }); |
| 185 |
| 186 test("MergeSortPreservesOrder", () { |
| 187 Random random = new Random(); |
| 188 // Small case where only insertion call is called, |
| 189 // larger case where the internal moving insertion sort is used |
| 190 // larger cases with multiple splittings, numbers just around a power of 2. |
| 191 for (int size in [8, 50, 511, 512, 513]) { |
| 192 List list = new List(size); |
| 193 // Class OC compares using id. |
| 194 // With size elements with id's in the range 0..size/4, a number of |
| 195 // collisions are guaranteed. These should be sorted so that the "order" |
| 196 // part of the objects are still in order. |
| 197 for (int i = 0; i < size; i++) { |
| 198 list[i] = new OC(random.nextInt(size >> 2), i); |
| 199 } |
| 200 mergeSort(list); |
| 201 OC prev = list[0]; |
| 202 for (int i = 1; i < size; i++) { |
| 203 OC next = list[i]; |
| 204 expect(prev.id, lessThanOrEqualTo(next.id)); |
| 205 if (next.id == prev.id) { |
| 206 expect(prev.order, lessThanOrEqualTo(next.order)); |
| 207 } |
| 208 prev = next; |
| 209 } |
| 210 // Reverse compare on part of list. |
| 211 List copy = list.toList(); |
| 212 int min = size >> 2; |
| 213 int max = size - min; |
| 214 mergeSort(list, start: min, end: max, compare: (a, b) => b.compareTo(a)); |
| 215 prev = list[min]; |
| 216 for (int i = min + 1; i < max; i++) { |
| 217 OC next = list[i]; |
| 218 expect(prev.id, greaterThanOrEqualTo(next.id)); |
| 219 if (next.id == prev.id) { |
| 220 expect(prev.order, lessThanOrEqualTo(next.order)); |
| 221 } |
| 222 prev = next; |
| 223 } |
| 224 // Equals on OC objects is identity, so this means the parts before min, |
| 225 // and the parts after max, didn't change at all. |
| 226 expect(list.sublist(0, min), equals(copy.sublist(0, min))); |
| 227 expect(list.sublist(max), equals(copy.sublist(max))); |
| 228 } |
| 229 }); |
| 230 |
| 231 test("MergeSortSpecialCases", () { |
| 232 for (int size in [511, 512, 513]) { |
| 233 // All equal. |
| 234 List list = new List(size); |
| 235 for (int i = 0; i < size; i++) { |
| 236 list[i] = new OC(0, i); |
| 237 } |
| 238 mergeSort(list); |
| 239 for (int i = 0; i < size; i++) { |
| 240 expect(list[i].order, equals(i)); |
| 241 } |
| 242 // All but one equal, first. |
| 243 list[0] = new OC(1, 0); |
| 244 for (int i = 1; i < size; i++) { |
| 245 list[i] = new OC(0, i); |
| 246 } |
| 247 mergeSort(list); |
| 248 for (int i = 0; i < size - 1; i++) { |
| 249 expect(list[i].order, equals(i + 1)); |
| 250 } |
| 251 expect(list[size - 1].order, equals(0)); |
| 252 |
| 253 // All but one equal, last. |
| 254 for (int i = 0; i < size - 1; i++) { |
| 255 list[i] = new OC(0, i); |
| 256 } |
| 257 list[size - 1] = new OC(-1, size - 1); |
| 258 mergeSort(list); |
| 259 expect(list[0].order, equals(size - 1)); |
| 260 for (int i = 1; i < size; i++) { |
| 261 expect(list[i].order, equals(i - 1)); |
| 262 } |
| 263 |
| 264 // Reversed. |
| 265 for (int i = 0; i < size; i++) { |
| 266 list[i] = new OC(size - 1 - i, i); |
| 267 } |
| 268 mergeSort(list); |
| 269 for (int i = 0; i < size; i++) { |
| 270 expect(list[i].id, equals(i)); |
| 271 expect(list[i].order, equals(size - 1 - i)); |
| 272 } |
| 273 } |
| 274 }); |
| 275 |
| 276 test("Reverse", () { |
| 277 List l = [6, 5, 4, 3, 2, 1]; |
| 278 reverse(l, 2, 4); |
| 279 expect(l, equals([6, 5, 3, 4, 2, 1])); |
| 280 reverse(l, 1, 1); |
| 281 expect(l, equals([6, 5, 3, 4, 2, 1])); |
| 282 reverse(l, 4, 6); |
| 283 expect(l, equals([6, 5, 3, 4, 1, 2])); |
| 284 reverse(l, 0, 2); |
| 285 expect(l, equals([5, 6, 3, 4, 1, 2])); |
| 286 reverse(l, 0, 6); |
| 287 expect(l, equals([2, 1, 4, 3, 6, 5])); |
| 288 }); |
| 289 } |
| 290 |
| 291 class C { |
| 292 final int id; |
| 293 C(this.id); |
| 294 } |
| 295 int compareC(C one, C other) => one.id - other.id; |
| 296 |
| 297 class OC implements Comparable<OC> { |
| 298 final int id; |
| 299 final int order; |
| 300 OC(this.id, this.order); |
| 301 int compareTo(OC other) => id - other.id; |
| 302 String toString() => "OC[$id,$order]"; |
| 303 } |
OLD | NEW |