Skip to content

Commit 0ef0809

Browse files
committed
Merge branch 'rs/mergesort'
The mergesort implementation used to sort linked list has been optimized. * rs/mergesort: test-mergesort: use repeatable random numbers mergesort: use ranks stack p0071: test performance of llist_mergesort() p0071: measure sorting of already sorted and reversed files test-mergesort: add unriffle_skewed mode test-mergesort: add unriffle mode test-mergesort: add generate subcommand test-mergesort: add test subcommand test-mergesort: add sort subcommand test-mergesort: use strbuf_getline()
2 parents f443b22 + c90cfc2 commit 0ef0809

File tree

4 files changed

+473
-67
lines changed

4 files changed

+473
-67
lines changed

mergesort.c

Lines changed: 66 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,84 @@
11
#include "cache.h"
22
#include "mergesort.h"
33

4-
struct mergesort_sublist {
5-
void *ptr;
6-
unsigned long len;
7-
};
8-
9-
static void *get_nth_next(void *list, unsigned long n,
10-
void *(*get_next_fn)(const void *))
4+
/* Combine two sorted lists. Take from `list` on equality. */
5+
static void *llist_merge(void *list, void *other,
6+
void *(*get_next_fn)(const void *),
7+
void (*set_next_fn)(void *, void *),
8+
int (*compare_fn)(const void *, const void *))
119
{
12-
while (n-- && list)
13-
list = get_next_fn(list);
14-
return list;
15-
}
10+
void *result = list, *tail;
1611

17-
static void *pop_item(struct mergesort_sublist *l,
18-
void *(*get_next_fn)(const void *))
19-
{
20-
void *p = l->ptr;
21-
l->ptr = get_next_fn(l->ptr);
22-
l->len = l->ptr ? (l->len - 1) : 0;
23-
return p;
12+
if (compare_fn(list, other) > 0) {
13+
result = other;
14+
goto other;
15+
}
16+
for (;;) {
17+
do {
18+
tail = list;
19+
list = get_next_fn(list);
20+
if (!list) {
21+
set_next_fn(tail, other);
22+
return result;
23+
}
24+
} while (compare_fn(list, other) <= 0);
25+
set_next_fn(tail, other);
26+
other:
27+
do {
28+
tail = other;
29+
other = get_next_fn(other);
30+
if (!other) {
31+
set_next_fn(tail, list);
32+
return result;
33+
}
34+
} while (compare_fn(list, other) > 0);
35+
set_next_fn(tail, list);
36+
}
2437
}
2538

39+
/*
40+
* Perform an iterative mergesort using an array of sublists.
41+
*
42+
* n is the number of items.
43+
* ranks[i] is undefined if n & 2^i == 0, and assumed empty.
44+
* ranks[i] contains a sublist of length 2^i otherwise.
45+
*
46+
* The number of bits in a void pointer limits the number of objects
47+
* that can be created, and thus the number of array elements necessary
48+
* to be able to sort any valid list.
49+
*
50+
* Adding an item to this array is like incrementing a binary number;
51+
* positional values for set bits correspond to sublist lengths.
52+
*/
2653
void *llist_mergesort(void *list,
2754
void *(*get_next_fn)(const void *),
2855
void (*set_next_fn)(void *, void *),
2956
int (*compare_fn)(const void *, const void *))
3057
{
31-
unsigned long l;
32-
33-
if (!list)
34-
return NULL;
35-
for (l = 1; ; l *= 2) {
36-
void *curr;
37-
struct mergesort_sublist p, q;
58+
void *ranks[bitsizeof(void *)];
59+
size_t n = 0;
60+
int i;
3861

39-
p.ptr = list;
40-
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
41-
if (!q.ptr)
42-
break;
43-
p.len = q.len = l;
62+
while (list) {
63+
void *next = get_next_fn(list);
64+
if (next)
65+
set_next_fn(list, NULL);
66+
for (i = 0; n & (1 << i); i++)
67+
list = llist_merge(ranks[i], list, get_next_fn,
68+
set_next_fn, compare_fn);
69+
n++;
70+
ranks[i] = list;
71+
list = next;
72+
}
4473

45-
if (compare_fn(p.ptr, q.ptr) > 0)
46-
list = curr = pop_item(&q, get_next_fn);
74+
for (i = 0; n; i++, n >>= 1) {
75+
if (!(n & 1))
76+
continue;
77+
if (list)
78+
list = llist_merge(ranks[i], list, get_next_fn,
79+
set_next_fn, compare_fn);
4780
else
48-
list = curr = pop_item(&p, get_next_fn);
49-
50-
while (p.ptr) {
51-
while (p.len || q.len) {
52-
void *prev = curr;
53-
54-
if (!p.len)
55-
curr = pop_item(&q, get_next_fn);
56-
else if (!q.len)
57-
curr = pop_item(&p, get_next_fn);
58-
else if (compare_fn(p.ptr, q.ptr) > 0)
59-
curr = pop_item(&q, get_next_fn);
60-
else
61-
curr = pop_item(&p, get_next_fn);
62-
set_next_fn(prev, curr);
63-
}
64-
p.ptr = q.ptr;
65-
p.len = l;
66-
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
67-
q.len = q.ptr ? l : 0;
68-
69-
}
70-
set_next_fn(curr, NULL);
81+
list = ranks[i];
7182
}
7283
return list;
7384
}

0 commit comments

Comments
 (0)