aboutsummaryrefslogtreecommitdiff
path: root/common/list.c
diff options
context:
space:
mode:
authorDenis Doria <denisdoria@gmail.com>2016-06-03 00:17:51 +0200
committerDenis Doria <denisdoria@gmail.com>2016-06-03 00:17:51 +0200
commit8a08e831947c8feecf8e79ecf21279c950ae419a (patch)
tree634c9197d6dd1dfebbb124d797f5c13b1c605a92 /common/list.c
parente4f80877bea48eb29b4ddfbce923bf78a6694ffb (diff)
parent68b517e1aee452463c7eff3775f8b56b0e48bc54 (diff)
Merge branch 'master' into variables_corner_cases
Diffstat (limited to 'common/list.c')
-rw-r--r--common/list.c59
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);
+ }
+}