| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart._internal; | 5 part of dart._internal; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Dual-Pivot Quicksort algorithm. | 8 * Dual-Pivot Quicksort algorithm. |
| 9 * | 9 * |
| 10 * This class implements the dual-pivot quicksort algorithm as presented in | 10 * This class implements the dual-pivot quicksort algorithm as presented in |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 static void sortRange<E>(List<E> a, int from, int to, int compare(E a, E b)) { | 45 static void sortRange<E>(List<E> a, int from, int to, int compare(E a, E b)) { |
| 46 if ((from < 0) || (to > a.length) || (to < from)) { | 46 if ((from < 0) || (to > a.length) || (to < from)) { |
| 47 throw "OutOfRange"; | 47 throw "OutOfRange"; |
| 48 } | 48 } |
| 49 _doSort(a, from, to - 1, compare); | 49 _doSort(a, from, to - 1, compare); |
| 50 } | 50 } |
| 51 | 51 |
| 52 /** | 52 /** |
| 53 * Sorts the list in the interval [:left:] to [:right:] (both inclusive). | 53 * Sorts the list in the interval [:left:] to [:right:] (both inclusive). |
| 54 */ | 54 */ |
| 55 static void _doSort<E>(List<E> a, int left, int right, | 55 static void _doSort<E>( |
| 56 int compare(E a, E b)) { | 56 List<E> a, int left, int right, int compare(E a, E b)) { |
| 57 if ((right - left) <= _INSERTION_SORT_THRESHOLD) { | 57 if ((right - left) <= _INSERTION_SORT_THRESHOLD) { |
| 58 _insertionSort(a, left, right, compare); | 58 _insertionSort(a, left, right, compare); |
| 59 } else { | 59 } else { |
| 60 _dualPivotQuicksort(a, left, right, compare); | 60 _dualPivotQuicksort(a, left, right, compare); |
| 61 } | 61 } |
| 62 } | 62 } |
| 63 | 63 |
| 64 static void _insertionSort<E>(List<E> a, int left, int right, | 64 static void _insertionSort<E>( |
| 65 int compare(E a, E b)) { | 65 List<E> a, int left, int right, int compare(E a, E b)) { |
| 66 for (int i = left + 1; i <= right; i++) { | 66 for (int i = left + 1; i <= right; i++) { |
| 67 var el = a[i]; | 67 var el = a[i]; |
| 68 int j = i; | 68 int j = i; |
| 69 while ((j > left) && (compare(a[j - 1], el) > 0)) { | 69 while ((j > left) && (compare(a[j - 1], el) > 0)) { |
| 70 a[j] = a[j - 1]; | 70 a[j] = a[j - 1]; |
| 71 j--; | 71 j--; |
| 72 } | 72 } |
| 73 a[j] = el; | 73 a[j] = el; |
| 74 } | 74 } |
| 75 } | 75 } |
| 76 | 76 |
| 77 static void _dualPivotQuicksort<E>(List<E> a, int left, int right, | 77 static void _dualPivotQuicksort<E>( |
| 78 int compare(E a, E b)) { | 78 List<E> a, int left, int right, int compare(E a, E b)) { |
| 79 assert(right - left > _INSERTION_SORT_THRESHOLD); | 79 assert(right - left > _INSERTION_SORT_THRESHOLD); |
| 80 | 80 |
| 81 // Compute the two pivots by looking at 5 elements. | 81 // Compute the two pivots by looking at 5 elements. |
| 82 int sixth = (right - left + 1) ~/ 6; | 82 int sixth = (right - left + 1) ~/ 6; |
| 83 int index1 = left + sixth; | 83 int index1 = left + sixth; |
| 84 int index5 = right - sixth; | 84 int index5 = right - sixth; |
| 85 int index3 = (left + right) ~/ 2; // The midpoint. | 85 int index3 = (left + right) ~/ 2; // The midpoint. |
| 86 int index2 = index3 - sixth; | 86 int index2 = index3 - sixth; |
| 87 int index4 = index3 + sixth; | 87 int index4 = index3 + sixth; |
| 88 | 88 |
| 89 var el1 = a[index1]; | 89 var el1 = a[index1]; |
| 90 var el2 = a[index2]; | 90 var el2 = a[index2]; |
| 91 var el3 = a[index3]; | 91 var el3 = a[index3]; |
| 92 var el4 = a[index4]; | 92 var el4 = a[index4]; |
| 93 var el5 = a[index5]; | 93 var el5 = a[index5]; |
| 94 | 94 |
| 95 // Sort the selected 5 elements using a sorting network. | 95 // Sort the selected 5 elements using a sorting network. |
| 96 if (compare(el1, el2) > 0) { var t = el1; el1 = el2; el2 = t; } | 96 if (compare(el1, el2) > 0) { |
| 97 if (compare(el4, el5) > 0) { var t = el4; el4 = el5; el5 = t; } | 97 var t = el1; |
| 98 if (compare(el1, el3) > 0) { var t = el1; el1 = el3; el3 = t; } | 98 el1 = el2; |
| 99 if (compare(el2, el3) > 0) { var t = el2; el2 = el3; el3 = t; } | 99 el2 = t; |
| 100 if (compare(el1, el4) > 0) { var t = el1; el1 = el4; el4 = t; } | 100 } |
| 101 if (compare(el3, el4) > 0) { var t = el3; el3 = el4; el4 = t; } | 101 if (compare(el4, el5) > 0) { |
| 102 if (compare(el2, el5) > 0) { var t = el2; el2 = el5; el5 = t; } | 102 var t = el4; |
| 103 if (compare(el2, el3) > 0) { var t = el2; el2 = el3; el3 = t; } | 103 el4 = el5; |
| 104 if (compare(el4, el5) > 0) { var t = el4; el4 = el5; el5 = t; } | 104 el5 = t; |
| 105 } |
| 106 if (compare(el1, el3) > 0) { |
| 107 var t = el1; |
| 108 el1 = el3; |
| 109 el3 = t; |
| 110 } |
| 111 if (compare(el2, el3) > 0) { |
| 112 var t = el2; |
| 113 el2 = el3; |
| 114 el3 = t; |
| 115 } |
| 116 if (compare(el1, el4) > 0) { |
| 117 var t = el1; |
| 118 el1 = el4; |
| 119 el4 = t; |
| 120 } |
| 121 if (compare(el3, el4) > 0) { |
| 122 var t = el3; |
| 123 el3 = el4; |
| 124 el4 = t; |
| 125 } |
| 126 if (compare(el2, el5) > 0) { |
| 127 var t = el2; |
| 128 el2 = el5; |
| 129 el5 = t; |
| 130 } |
| 131 if (compare(el2, el3) > 0) { |
| 132 var t = el2; |
| 133 el2 = el3; |
| 134 el3 = t; |
| 135 } |
| 136 if (compare(el4, el5) > 0) { |
| 137 var t = el4; |
| 138 el4 = el5; |
| 139 el5 = t; |
| 140 } |
| 105 | 141 |
| 106 var pivot1 = el2; | 142 var pivot1 = el2; |
| 107 var pivot2 = el4; | 143 var pivot2 = el4; |
| 108 | 144 |
| 109 // el2 and el4 have been saved in the pivot variables. They will be written | 145 // el2 and el4 have been saved in the pivot variables. They will be written |
| 110 // back, once the partitioning is finished. | 146 // back, once the partitioning is finished. |
| 111 a[index1] = el1; | 147 a[index1] = el1; |
| 112 a[index3] = el3; | 148 a[index3] = el3; |
| 113 a[index5] = el5; | 149 a[index5] = el5; |
| 114 | 150 |
| 115 a[index2] = a[left]; | 151 a[index2] = a[left]; |
| 116 a[index4] = a[right]; | 152 a[index4] = a[right]; |
| 117 | 153 |
| 118 int less = left + 1; // First element in the middle partition. | 154 int less = left + 1; // First element in the middle partition. |
| 119 int great = right - 1; // Last element in the middle partition. | 155 int great = right - 1; // Last element in the middle partition. |
| 120 | 156 |
| 121 bool pivots_are_equal = (compare(pivot1, pivot2) == 0); | 157 bool pivots_are_equal = (compare(pivot1, pivot2) == 0); |
| 122 if (pivots_are_equal) { | 158 if (pivots_are_equal) { |
| 123 var pivot = pivot1; | 159 var pivot = pivot1; |
| 124 // Degenerated case where the partitioning becomes a dutch national flag | 160 // Degenerated case where the partitioning becomes a dutch national flag |
| 125 // problem. | 161 // problem. |
| 126 // | 162 // |
| 127 // [ | < pivot | == pivot | unpartitioned | > pivot | ] | 163 // [ | < pivot | == pivot | unpartitioned | > pivot | ] |
| 128 // ^ ^ ^ ^ ^ | 164 // ^ ^ ^ ^ ^ |
| 129 // left less k great right | 165 // left less k great right |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 // All elements in the second partition are equal to the pivot. No | 297 // All elements in the second partition are equal to the pivot. No |
| 262 // need to sort them. | 298 // need to sort them. |
| 263 return; | 299 return; |
| 264 } | 300 } |
| 265 | 301 |
| 266 // In theory it should be enough to call _doSort recursively on the second | 302 // In theory it should be enough to call _doSort recursively on the second |
| 267 // partition. | 303 // partition. |
| 268 // The Android source however removes the pivot elements from the recursive | 304 // The Android source however removes the pivot elements from the recursive |
| 269 // call if the second partition is too large (more than 2/3 of the list). | 305 // call if the second partition is too large (more than 2/3 of the list). |
| 270 if (less < index1 && great > index5) { | 306 if (less < index1 && great > index5) { |
| 271 while (compare(a[less], pivot1) == 0) { less++; } | 307 while (compare(a[less], pivot1) == 0) { |
| 272 while (compare(a[great], pivot2) == 0) { great--; } | 308 less++; |
| 309 } |
| 310 while (compare(a[great], pivot2) == 0) { |
| 311 great--; |
| 312 } |
| 273 | 313 |
| 274 // Copy paste of the previous 3-way partitioning with adaptions. | 314 // Copy paste of the previous 3-way partitioning with adaptions. |
| 275 // | 315 // |
| 276 // We partition the list into three parts: | 316 // We partition the list into three parts: |
| 277 // 1. == pivot1 | 317 // 1. == pivot1 |
| 278 // 2. > pivot1 && < pivot2 | 318 // 2. > pivot1 && < pivot2 |
| 279 // 3. == pivot2 | 319 // 3. == pivot2 |
| 280 // | 320 // |
| 281 // During the loop we have: | 321 // During the loop we have: |
| 282 // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ] | 322 // [ == pivot1 | > pivot1 && < pivot2 | unpartitioned | == pivot2 ] |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 } else { | 376 } else { |
| 337 // The second partition looks as follows: | 377 // The second partition looks as follows: |
| 338 // [ * | >= pivot1 && <= pivot2 | * ] | 378 // [ * | >= pivot1 && <= pivot2 | * ] |
| 339 // ^ ^ | 379 // ^ ^ |
| 340 // less great | 380 // less great |
| 341 // Simply sort it by recursive descent. | 381 // Simply sort it by recursive descent. |
| 342 _doSort(a, less, great, compare); | 382 _doSort(a, less, great, compare); |
| 343 } | 383 } |
| 344 } | 384 } |
| 345 } | 385 } |
| OLD | NEW |