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>
This commit is contained in:
parent
828ea97de4
commit
0db71e0fa9
1
.gitignore
vendored
1
.gitignore
vendored
@ -180,6 +180,7 @@
|
||||
/test-index-version
|
||||
/test-line-buffer
|
||||
/test-match-trees
|
||||
/test-mergesort
|
||||
/test-mktemp
|
||||
/test-obj-pool
|
||||
/test-parse-options
|
||||
|
3
Makefile
3
Makefile
@ -465,6 +465,7 @@ TEST_PROGRAMS_NEED_X += test-genrandom
|
||||
TEST_PROGRAMS_NEED_X += test-index-version
|
||||
TEST_PROGRAMS_NEED_X += test-line-buffer
|
||||
TEST_PROGRAMS_NEED_X += test-match-trees
|
||||
TEST_PROGRAMS_NEED_X += test-mergesort
|
||||
TEST_PROGRAMS_NEED_X += test-mktemp
|
||||
TEST_PROGRAMS_NEED_X += test-obj-pool
|
||||
TEST_PROGRAMS_NEED_X += test-parse-options
|
||||
@ -578,6 +579,7 @@ LIB_H += log-tree.h
|
||||
LIB_H += mailmap.h
|
||||
LIB_H += merge-file.h
|
||||
LIB_H += merge-recursive.h
|
||||
LIB_H += mergesort.h
|
||||
LIB_H += notes.h
|
||||
LIB_H += notes-cache.h
|
||||
LIB_H += notes-merge.h
|
||||
@ -681,6 +683,7 @@ LIB_OBJS += mailmap.o
|
||||
LIB_OBJS += match-trees.o
|
||||
LIB_OBJS += merge-file.o
|
||||
LIB_OBJS += merge-recursive.o
|
||||
LIB_OBJS += mergesort.o
|
||||
LIB_OBJS += name-hash.o
|
||||
LIB_OBJS += notes.o
|
||||
LIB_OBJS += notes-cache.o
|
||||
|
73
mergesort.c
Normal file
73
mergesort.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "cache.h"
|
||||
#include "mergesort.h"
|
||||
|
||||
struct mergesort_sublist {
|
||||
void *ptr;
|
||||
unsigned long len;
|
||||
};
|
||||
|
||||
static void *get_nth_next(void *list, unsigned long n,
|
||||
void *(*get_next_fn)(const void *))
|
||||
{
|
||||
while (n-- && list)
|
||||
list = get_next_fn(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
static void *pop_item(struct mergesort_sublist *l,
|
||||
void *(*get_next_fn)(const void *))
|
||||
{
|
||||
void *p = l->ptr;
|
||||
l->ptr = get_next_fn(l->ptr);
|
||||
l->len = l->ptr ? (l->len - 1) : 0;
|
||||
return p;
|
||||
}
|
||||
|
||||
void *mergesort(void *list,
|
||||
void *(*get_next_fn)(const void *),
|
||||
void (*set_next_fn)(void *, void *),
|
||||
int (*compare_fn)(const void *, const void *))
|
||||
{
|
||||
unsigned long l;
|
||||
|
||||
if (!list)
|
||||
return NULL;
|
||||
for (l = 1; ; l *= 2) {
|
||||
void *curr;
|
||||
struct mergesort_sublist p, q;
|
||||
|
||||
p.ptr = list;
|
||||
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
|
||||
if (!q.ptr)
|
||||
break;
|
||||
p.len = q.len = l;
|
||||
|
||||
if (compare_fn(p.ptr, q.ptr) > 0)
|
||||
list = curr = pop_item(&q, get_next_fn);
|
||||
else
|
||||
list = curr = pop_item(&p, get_next_fn);
|
||||
|
||||
while (p.ptr) {
|
||||
while (p.len || q.len) {
|
||||
void *prev = curr;
|
||||
|
||||
if (!p.len)
|
||||
curr = pop_item(&q, get_next_fn);
|
||||
else if (!q.len)
|
||||
curr = pop_item(&p, get_next_fn);
|
||||
else if (compare_fn(p.ptr, q.ptr) > 0)
|
||||
curr = pop_item(&q, get_next_fn);
|
||||
else
|
||||
curr = pop_item(&p, get_next_fn);
|
||||
set_next_fn(prev, curr);
|
||||
}
|
||||
p.ptr = q.ptr;
|
||||
p.len = l;
|
||||
q.ptr = get_nth_next(p.ptr, l, get_next_fn);
|
||||
q.len = q.ptr ? l : 0;
|
||||
|
||||
}
|
||||
set_next_fn(curr, NULL);
|
||||
}
|
||||
return list;
|
||||
}
|
9
mergesort.h
Normal file
9
mergesort.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef MERGESORT_H
|
||||
#define MERGESORT_H
|
||||
|
||||
void *mergesort(void *list,
|
||||
void *(*get_next_fn)(const void *),
|
||||
void (*set_next_fn)(void *, void *),
|
||||
int (*compare_fn)(const void *, const void *));
|
||||
|
||||
#endif
|
52
test-mergesort.c
Normal file
52
test-mergesort.c
Normal file
@ -0,0 +1,52 @@
|
||||
#include "cache.h"
|
||||
#include "mergesort.h"
|
||||
|
||||
struct line {
|
||||
char *text;
|
||||
struct line *next;
|
||||
};
|
||||
|
||||
static void *get_next(const void *a)
|
||||
{
|
||||
return ((const struct line *)a)->next;
|
||||
}
|
||||
|
||||
static void set_next(void *a, void *b)
|
||||
{
|
||||
((struct line *)a)->next = b;
|
||||
}
|
||||
|
||||
static int compare_strings(const void *a, const void *b)
|
||||
{
|
||||
const struct line *x = a, *y = b;
|
||||
return strcmp(x->text, y->text);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
struct line *line, *p = NULL, *lines = NULL;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
for (;;) {
|
||||
if (strbuf_getwholeline(&sb, stdin, '\n'))
|
||||
break;
|
||||
line = xmalloc(sizeof(struct line));
|
||||
line->text = strbuf_detach(&sb, NULL);
|
||||
if (p) {
|
||||
line->next = p->next;
|
||||
p->next = line;
|
||||
} else {
|
||||
line->next = NULL;
|
||||
lines = line;
|
||||
}
|
||||
p = line;
|
||||
}
|
||||
|
||||
lines = mergesort(lines, get_next, set_next, compare_strings);
|
||||
|
||||
while (lines) {
|
||||
printf("%s", lines->text);
|
||||
lines = lines->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user