-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsort.c
68 lines (60 loc) · 1.79 KB
/
msort.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdlib.h>
struct mergesort_sublist {
void *list;
unsigned long length;
};
static void *get_nth_next(void *list, unsigned long n, void *(*get_next_fn)(void const *));
static void *pop_item(struct mergesort_sublist *list, void *(*get_next_fn)(void const *));
void *
mergesort(void *list, void *(*get_next_fn)(void const *), void (*set_next_fn)(void *, void *),
int (*compare_fn)(void const *, void const *)) {
unsigned long l;
if (!list)
return NULL;
for (l = 1;; l *= 2) {
void *current;
struct mergesort_sublist p, q;
p.list = list;
q.list = get_nth_next(p.list, l, get_next_fn);
if (!q.list)
break;
p.length = q.length = l;
if (compare_fn(p.list, q.list) > 0)
list = current = pop_item(&q, get_next_fn);
else
list = current = pop_item(&p, get_next_fn);
while (p.list) {
while (p.length || q.length) {
void *prev = current;
if (!p.length)
current = pop_item(&q, get_next_fn);
else if (!q.length)
current = pop_item(&p, get_next_fn);
else if (compare_fn(p.list, q.list) > 0)
current = pop_item(&q, get_next_fn);
else
current = pop_item(&p, get_next_fn);
set_next_fn(prev, current);
}
p.list = q.list;
p.length = l;
q.list = get_nth_next(p.list, l, get_next_fn);
q.length = q.list ? l : 0;
}
set_next_fn(current, NULL);
}
return list;
}
static void *
get_nth_next(void *list, unsigned long n, void *(*get_next_fn)(void const *)) {
while (n-- && list)
list = get_next_fn(list);
return list;
}
static void *
pop_item(struct mergesort_sublist *l, void *(*get_next_fn)(void const *)) {
void *p = l->list;
l->list = get_next_fn(l->list);
l->length = l->list ? (l->length - 1) : 0;
return p;
}