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 |