3 * Copyright (C) 2009 Didier Villevalois
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
24 * A stable, adaptive, iterative mergesort that requires far fewer than n*lg(n)
25 * comparisons when running on partially sorted arrays, while offering
26 * performance comparable to a traditional mergesort when run on random arrays.
27 * Like all proper mergesorts, this sort is stable and runs O(n*log(n)) time
28 * (worst case). In the worst case, this sort requires temporary storage space
29 * for n/2 object references; in the best case, it requires only a small
30 * constant amount of space.
32 * This implementation was adapted from Tim Peters's list sort for Python,
33 * which is described in detail here:
34 * [[http://svn.python.org/projects/python/trunk/Objects/listsort.txt]]
36 * Tim's C code may be found here:
37 * [[http://svn.python.org/projects/python/trunk/Objects/listobject.c]]
39 * The underlying techniques are described in this paper (and may have even
42 * "Optimistic Sorting and Information Theoretic Complexity"
44 * SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), pp
45 * 467-474, Austin, Texas, 25-27 January 1993.
47 internal class Vala
.TimSort
<G
> {
49 public static void sort
<G
> (List
<G
> list
, CompareDataFunc
<G
> compare
) {
50 if (list is ArrayList
) {
51 TimSort
.sort_arraylist
<G
> ((ArrayList
<G
>) list
, compare
);
53 TimSort
.sort_list
<G
> (list
, compare
);
57 private static void sort_list
<G
> (List
<G
> list
, CompareDataFunc
<G
> compare
) {
58 TimSort
<G
> helper
= new TimSort
<G
> ();
60 helper
.list_collection
= list
;
61 helper
.array
= list
.to_array ();
62 helper
.list
= helper
.array
;
64 helper
.size
= list
.size
;
65 helper
.compare
= compare
;
69 // TODO Use a list iterator and use iter.set (item)
71 foreach (G item
in helper
.array
) {
76 private static void sort_arraylist
<G
> (ArrayList
<G
> list
, CompareDataFunc
<G
> compare
) {
77 TimSort
<G
> helper
= new TimSort
<G
> ();
79 helper
.list_collection
= list
;
80 helper
.list
= list
._items
;
82 helper
.size
= list
._size
;
83 helper
.compare
= compare
;
88 private const int MINIMUM_GALLOP
= 7;
90 private List
<G
> list_collection
;
95 private Slice
<G
>[] pending
;
96 private int minimum_gallop
;
97 private unowned CompareDataFunc
<G
> compare
;
99 private void do_sort () {
104 pending
= new Slice
<G
>[0];
105 minimum_gallop
= MINIMUM_GALLOP
;
107 Slice
<G
> remaining
= new Slice
<G
> (list
, index
, size
);
108 int minimum_length
= compute_minimum_run_length (remaining
.length
);
110 while (remaining
.length
> 0) {
113 Slice
<G
> run
= compute_longest_run (remaining
, out descending
);
115 message ("New run (%d, %d) %s", run
.index
, run
.length
,
116 descending ?
"descending" : "ascending");
122 // Extend it to minimum_length, if needed
123 if (run
.length
< minimum_length
) {
124 int sorted_count
= run
.length
;
125 run
.length
= int.min (minimum_length
, remaining
.length
);
126 insertion_sort (run
, sorted_count
);
128 message ("Extended to (%d, %d) and sorted from index %d",
129 run
.index
, run
.length
, sorted_count
);
133 // Move remaining after run
134 remaining
.shorten_start (run
.length
);
136 // Add run to pending runs and try to merge
137 pending
+= (owned
) run
;
141 assert (remaining
.index
== size
);
143 merge_force_collapse ();
145 assert (pending
.length
== 1);
146 assert (pending
[0].index
== 0);
147 assert (pending
[0].length
== size
);
150 private delegate
bool LowerFunc (G left
, G right
);
152 private inline
bool lower_than (G left
, G right
) {
153 return compare (left
, right
) < 0;
156 private inline
bool lower_than_or_equal_to (G left
, G right
) {
157 return compare (left
, right
) <= 0;
160 private int compute_minimum_run_length (int length
) {
162 while (length
>= 64) {
163 run_length
|= length
& 1;
166 return length
+ run_length
;
169 private Slice
<G
> compute_longest_run (Slice
<G
> a
, out bool descending
) {
172 run_length
= a
.length
;
176 if (lower_than (a
.list
[a
.index
+ 1], a
.list
[a
.index
])) {
178 for (int i
= a
.index
+ 2; i
< a
.index
+ a
.length
; i
++) {
179 if (lower_than (a
.list
[i
], a
.list
[i
-1])) {
187 for (int i
= a
.index
+ 2; i
< a
.index
+ a
.length
; i
++) {
188 if (lower_than (a
.list
[i
], a
.list
[i
-1])) {
196 return new Slice
<G
> (a
.list
, a
.index
, run_length
);
199 private void insertion_sort (Slice
<G
> a
, int offset
) {
201 message ("Sorting (%d, %d) at %d", a
.index
, a
.length
, offset
);
203 for (int start
= a
.index
+ offset
; start
< a
.index
+ a
.length
; start
++) {
206 void* pivot
= a
.list
[right
];
208 while (left
< right
) {
209 int p
= left
+ ((right
- left
) >> 1);
210 if (lower_than (pivot
, a
.list
[p
])) {
216 assert (left
== right
);
218 Memory
.move (&a
.list
[left
+ 1], &a
.list
[left
], sizeof (G
) * (start
- left
));
219 a
.list
[left
] = pivot
;
223 private void merge_collapse () {
225 message ("Merge Collapse");
227 int count
= pending
.length
;
230 message ("Pending count: %d", count
);
232 message ("pending[count-3]=%p; pending[count-2]=%p; pending[count-1]=%p",
233 pending
[count
-3], pending
[count
-2], pending
[count
-1]);
236 if (count
>= 3 && pending
[count
-3].length
<= pending
[count
-2].length
+ pending
[count
-1].length
) {
237 if (pending
[count
-3].length
< pending
[count
-1].length
) {
242 } else if (pending
[count
-2].length
<= pending
[count
-1].length
) {
247 count
= pending
.length
;
249 message ("New pending count: %d", count
);
254 private void merge_force_collapse () {
256 message ("Merge Force Collapse");
258 int count
= pending
.length
;
260 message ("Pending count: %d", count
);
263 if (count
>= 3 && pending
[count
-3].length
< pending
[count
-1].length
) {
268 count
= pending
.length
;
270 message ("New pending count: %d", count
);
275 private void merge_at (int index
) {
277 message ("Merge at %d", index
);
279 Slice
<G
> a
= (owned
) pending
[index
];
280 Slice
<G
> b
= (owned
) pending
[index
+ 1];
282 assert (a
.length
> 0);
283 assert (b
.length
> 0);
284 assert (a
.index
+ a
.length
== b
.index
);
286 pending
[index
] = new Slice
<G
> (list
, a
.index
, a
.length
+ b
.length
);
287 pending
.move (index
+ 2, index
+ 1, pending
.length
- index
- 2);
290 int sorted_count
= gallop_rightmost (b
.peek_first (), a
, 0);
291 a
.shorten_start (sorted_count
);
296 b
.length
= gallop_leftmost (a
.peek_last (), b
, b
.length
- 1);
301 if (a
.length
<= b
.length
) {
302 merge_low ((owned
) a
, (owned
) b
);
304 merge_high ((owned
) a
, (owned
) b
);
308 private int gallop_leftmost (G key
, Slice
<G
> a
, int hint
) {
310 message ("Galop leftmost in (%d, %d), hint=%d", a
.index
, a
.length
, hint
);
313 assert (hint
< a
.length
);
315 int p
= a
.index
+ hint
;
318 if (lower_than (a
.list
[p
], key
)) {
319 int max_offset
= a
.length
- hint
;
320 while (offset
< max_offset
) {
321 if (lower_than (a
.list
[p
+ offset
], key
)) {
322 last_offset
= offset
;
330 if (offset
> max_offset
) {
334 last_offset
= hint
+ last_offset
;
335 offset
= hint
+ offset
;
337 int max_offset
= hint
+ 1;
338 while (offset
< max_offset
) {
339 if (lower_than (a
.list
[p
- offset
], key
)) {
342 last_offset
= offset
;
348 if (offset
> max_offset
) {
352 int temp_last_offset
= last_offset
;
353 int temp_offset
= offset
;
354 last_offset
= hint
- temp_offset
;
355 offset
= hint
- temp_last_offset
;
358 assert (-1 <= last_offset
);
359 assert (last_offset
< offset
);
360 assert (offset
<= a
.length
);
363 while (last_offset
< offset
) {
364 int m
= last_offset
+ ((offset
- last_offset
) >> 1);
365 if (lower_than (a
.list
[a
.index
+ m
], key
)) {
372 assert (last_offset
== offset
);
376 private int gallop_rightmost (G key
, Slice
<G
> a
, int hint
) {
378 message ("Galop rightmost in (%d, %d), hint=%d", a
.index
, a
.length
, hint
);
381 assert (hint
< a
.length
);
383 int p
= a
.index
+ hint
;
386 if (lower_than_or_equal_to (a
.list
[p
], key
)) {
387 int max_offset
= a
.length
- hint
;
388 while (offset
< max_offset
) {
389 if (lower_than_or_equal_to (a
.list
[p
+ offset
], key
)) {
390 last_offset
= offset
;
398 if (offset
> max_offset
) {
402 last_offset
= hint
+ last_offset
;
403 offset
= hint
+ offset
;
405 int max_offset
= hint
+ 1;
406 while (offset
< max_offset
) {
407 if (lower_than_or_equal_to (a
.list
[p
- offset
], key
)) {
410 last_offset
= offset
;
416 if (offset
> max_offset
) {
420 int temp_last_offset
= last_offset
;
421 int temp_offset
= offset
;
422 last_offset
= hint
- temp_offset
;
423 offset
= hint
- temp_last_offset
;
426 assert (-1 <= last_offset
);
427 assert (last_offset
< offset
);
428 assert (offset
<= a
.length
);
431 while (last_offset
< offset
) {
432 int m
= last_offset
+ ((offset
- last_offset
) >> 1);
433 if (lower_than_or_equal_to (a
.list
[a
.index
+ m
], key
)) {
440 assert (last_offset
== offset
);
444 private void merge_low (owned Slice
<G
> a
, owned Slice
<G
> b
) {
446 message ("Merge low (%d, %d) (%d, %d)", a
.index
, a
.length
, b
.index
, b
.length
);
448 assert (a
.length
> 0);
449 assert (b
.length
> 0);
450 assert (a
.index
+ a
.length
== b
.index
);
452 int minimum_gallop
= this
.minimum_gallop
;
457 list
[dest
++] = b
.pop_first ();
458 if (a
.length
== 1 || b
.length
== 0) {
467 if (lower_than (b
.peek_first (), a
.peek_first ())) {
468 list
[dest
++] = b
.pop_first ();
475 if (b_count
>= minimum_gallop
) {
479 list
[dest
++] = a
.pop_first ();
486 if (a_count
>= minimum_gallop
) {
495 minimum_gallop
-= (minimum_gallop
> 1 ?
1 : 0);
496 this
.minimum_gallop
= minimum_gallop
;
498 a_count
= gallop_rightmost (b
.peek_first (), a
, 0);
499 a
.merge_in (list
, a
.index
, dest
, a_count
);
501 a
.shorten_start (a_count
);
506 list
[dest
++] = b
.pop_first ();
511 b_count
= gallop_leftmost (a
.peek_first (), b
, 0);
512 b
.merge_in (list
, b
.index
, dest
, b_count
);
514 b
.shorten_start (b_count
);
519 list
[dest
++] = a
.pop_first ();
524 if (a_count
< MINIMUM_GALLOP
&& b_count
< MINIMUM_GALLOP
) {
530 this
.minimum_gallop
= minimum_gallop
;
533 assert (a
.length
>= 0);
534 assert (b
.length
>= 0);
535 b
.merge_in (list
, b
.index
, dest
, b
.length
);
536 a
.merge_in (list
, a
.index
, dest
+ b
.length
, a
.length
);
540 private void merge_high (owned Slice
<G
> a
, owned Slice
<G
> b
) {
542 message ("Merge high (%d, %d) (%d, %d)", a
.index
, a
.length
, b
.index
, b
.length
);
544 assert (a
.length
> 0);
545 assert (b
.length
> 0);
546 assert (a
.index
+ a
.length
== b
.index
);
548 int minimum_gallop
= this
.minimum_gallop
;
549 int dest
= b
.index
+ b
.length
;
553 list
[--dest
] = a
.pop_last ();
554 if (a
.length
== 0 || b
.length
== 1) {
563 if (lower_than (b
.peek_last (), a
.peek_last ())) {
564 list
[--dest
] = a
.pop_last ();
571 if (a_count
>= minimum_gallop
) {
575 list
[--dest
] = b
.pop_last ();
582 if (b_count
>= minimum_gallop
) {
591 minimum_gallop
-= (minimum_gallop
> 1 ?
1 : 0);
592 this
.minimum_gallop
= minimum_gallop
;
594 int k
= gallop_rightmost (b
.peek_last (), a
, a
.length
- 1);
595 a_count
= a
.length
- k
;
596 a
.merge_in_reversed (list
, a
.index
+ k
, dest
- a_count
, a_count
);
598 a
.shorten_end (a_count
);
603 list
[--dest
] = b
.pop_last ();
608 k
= gallop_leftmost (a
.peek_last (), b
, b
.length
- 1);
609 b_count
= b
.length
- k
;
610 b
.merge_in_reversed (list
, b
.index
+ k
, dest
- b_count
, b_count
);
612 b
.shorten_end (b_count
);
617 list
[--dest
] = a
.pop_last ();
622 if (a_count
< MINIMUM_GALLOP
&& b_count
< MINIMUM_GALLOP
) {
628 this
.minimum_gallop
= minimum_gallop
;
631 assert (a
.length
>= 0);
632 assert (b
.length
>= 0);
633 a
.merge_in_reversed (list
, a
.index
, dest
- a
.length
, a
.length
);
634 b
.merge_in_reversed (list
, b
.index
, dest
- a
.length
- b
.length
, b
.length
);
639 private class Slice
<G
> {
642 public void** new_list
;
646 public Slice (void** list
, int index
, int length
) {
649 this
.length
= length
;
653 if (new_list
!= null)
657 public void copy () {
658 new_list
= Memory
.dup (&list
[index
], (uint) sizeof (G
) * length
);
663 public inline
void merge_in (void** dest_array
, int index
, int dest_index
, int count
) {
664 Memory
.move (&dest_array
[dest_index
], &list
[index
], sizeof (G
) * count
);
667 public inline
void merge_in_reversed (void** dest_array
, int index
, int dest_index
, int count
) {
668 Memory
.move (&dest_array
[dest_index
], &list
[index
], sizeof (G
) * count
);
671 public inline
void shorten_start (int n
) {
676 public inline
void shorten_end (int n
) {
680 public inline
void* pop_first () {
682 return list
[index
++];
685 public inline
void* pop_last () {
687 return list
[index
+ length
];
690 public inline unowned
void* peek_first () {
694 public inline unowned
void* peek_last () {
695 return list
[index
+ length
- 1];
698 public void reverse () {
700 int high
= index
+ length
- 1;
702 swap (low
++, high
--);
706 private inline
void swap (int i
, int j
) {
707 void* temp
= list
[i
];