add mergesort() for linked lists
This adds a generic bottom-up mergesort implementation for singly linked lists. It was inspired by Simon Tatham's webpage on the topic[1], but not so much by his implementation -- for no good reason, really, just a case of NIH. [1] http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
René Scharfe committed
Apr 1, 2012 at 00:10 UTC
0db71e0fa94c1857f98890928098e8f4c8ac6f26
5 files changed
+138
.gitignore
+1
@@ -180,6 +180,7 @@
180
/test-index-version
181
/test-line-buffer
182
/test-match-trees
183
+/test-mergesort
184
/test-mktemp
185
/test-obj-pool
186
/test-parse-options
Makefile
+3
@@ -465,6 +465,7 @@ TEST_PROGRAMS_NEED_X += test-genrandom
465
TEST_PROGRAMS_NEED_X += test-index-version
466
TEST_PROGRAMS_NEED_X += test-line-buffer
467
TEST_PROGRAMS_NEED_X += test-match-trees
468
+TEST_PROGRAMS_NEED_X += test-mergesort
469
TEST_PROGRAMS_NEED_X += test-mktemp
470
TEST_PROGRAMS_NEED_X += test-obj-pool
471
TEST_PROGRAMS_NEED_X += test-parse-options
@@ -578,6 +579,7 @@ LIB_H += log-tree.h
579
LIB_H += mailmap.h
580
LIB_H += merge-file.h
581
LIB_H += merge-recursive.h
582
+LIB_H += mergesort.h
583
LIB_H += notes.h
584
LIB_H += notes-cache.h
585
LIB_H += notes-merge.h
@@ -681,6 +683,7 @@ LIB_OBJS += mailmap.o
683
LIB_OBJS += match-trees.o
684
LIB_OBJS += merge-file.o
685
LIB_OBJS += merge-recursive.o
686
+LIB_OBJS += mergesort.o
687
LIB_OBJS += name-hash.o
688
LIB_OBJS += notes.o
689
LIB_OBJS += notes-cache.o
mergesort.c
new
+73
@@ -0,0 +1,73 @@
1
+#include "cache.h"
2
+#include "mergesort.h"
3
+
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 *))
11
+{
12
+ while (n-- && list)
13
+ list = get_next_fn(list);
14
+ return list;
15
+}
16
+
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;
24
+}
25
+
26
+void *mergesort(void *list,
27
+ void *(*get_next_fn)(const void *),
28
+ void (*set_next_fn)(void *, void *),
29
+ int (*compare_fn)(const void *, const void *))
30
+{
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;
38
+
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;
44
+
45
+ if (compare_fn(p.ptr, q.ptr) > 0)
46
+ list = curr = pop_item(&q, get_next_fn);
47
+ 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);
71
+ }
72
+ return list;
73
+}
mergesort.h
new
+9
@@ -0,0 +1,9 @@
1
+#ifndef MERGESORT_H
2
+#define MERGESORT_H
3
+
4
+void *mergesort(void *list,
5
+ void *(*get_next_fn)(const void *),
6
+ void (*set_next_fn)(void *, void *),
7
+ int (*compare_fn)(const void *, const void *));
8
+
9
+#endif
test-mergesort.c
new
+52
@@ -0,0 +1,52 @@
1
+#include "cache.h"
2
+#include "mergesort.h"
3
+
4
+struct line {
5
+ char *text;
6
+ struct line *next;
7
+};
8
+
9
+static void *get_next(const void *a)
10
+{
11
+ return ((const struct line *)a)->next;
12
+}
13
+
14
+static void set_next(void *a, void *b)
15
+{
16
+ ((struct line *)a)->next = b;
17
+}
18
+
19
+static int compare_strings(const void *a, const void *b)
20
+{
21
+ const struct line *x = a, *y = b;
22
+ return strcmp(x->text, y->text);
23
+}
24
+
25
+int main(int argc, const char **argv)
26
+{
27
+ struct line *line, *p = NULL, *lines = NULL;
28
+ struct strbuf sb = STRBUF_INIT;
29
+
30
+ for (;;) {
31
+ if (strbuf_getwholeline(&sb, stdin, '\n'))
32
+ break;
33
+ line = xmalloc(sizeof(struct line));
34
+ line->text = strbuf_detach(&sb, NULL);
35
+ if (p) {
36
+ line->next = p->next;
37
+ p->next = line;
38
+ } else {
39
+ line->next = NULL;
40
+ lines = line;
41
+ }
42
+ p = line;
43
+ }
44
+
45
+ lines = mergesort(lines, get_next, set_next, compare_strings);
46
+
47
+ while (lines) {
48
+ printf("%s", lines->text);
49
+ lines = lines->next;
50
+ }
51
+ return 0;
52
+}