diff options
Diffstat (limited to 'common/list.c')
-rw-r--r-- | common/list.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/common/list.c b/common/list.c index a7585a31..d57234e3 100644 --- a/common/list.c +++ b/common/list.c @@ -59,7 +59,7 @@ void list_cat(list_t *list, list_t *source) { } } -void list_qsort(list_t* list, int compare(const void *left, const void *right)) { +void list_qsort(list_t *list, int compare(const void *left, const void *right)) { qsort(list->items, list->length, sizeof(void *), compare); } @@ -72,3 +72,60 @@ int list_seq_find(list_t *list, int compare(const void *item, const void *data), } return -1; } + +static void list_swap(list_t *list, int src, int dest) { + void *tmp = list->items[src]; + list->items[src] = list->items[dest]; + list->items[dest] = tmp; +} + +static void list_rotate(list_t *list, int from, int to) { + void *tmp = list->items[to]; + + while (to > from) { + list->items[to] = list->items[to - 1]; + to--; + } + + list->items[from] = tmp; +} + +static void list_inplace_merge(list_t *list, int left, int last, int mid, int compare(const void *a, const void *b)) { + int right = mid + 1; + + if (compare(&list->items[mid], &list->items[right]) <= 0) { + return; + } + + while (left <= mid && right <= last) { + if (compare(&list->items[left], &list->items[right]) <= 0) { + left++; + } else { + list_rotate(list, left, right); + left++; + mid++; + right++; + } + } +} + +static void list_inplace_sort(list_t *list, int first, int last, int compare(const void *a, const void *b)) { + if (first >= last) { + return; + } else if ((last - first) == 1) { + if (compare(&list->items[first], &list->items[last]) > 0) { + list_swap(list, first, last); + } + } else { + int mid = (int)((last + first) / 2); + list_inplace_sort(list, first, mid, compare); + list_inplace_sort(list, mid + 1, last, compare); + list_inplace_merge(list, first, last, mid, compare); + } +} + +void list_stable_sort(list_t *list, int compare(const void *a, const void *b)) { + if (list->length > 1) { + list_inplace_sort(list, 0, list->length - 1, compare); + } +} |