Browse code

Add merge sort.

Xavier G authored on 25/08/2016 01:57:18
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,87 @@
1
+/**
2
+ * Copyright © 2016 Xavier G. <xavier@kindwolf.org>
3
+ * This work is free. You can redistribute it and/or modify it under the
4
+ * terms of the Do What The Fuck You Want To Public License, Version 2,
5
+ * as published by Sam Hocevar. See the COPYING file for more details.
6
+ */
7
+
8
+void array_sort(unsigned int **array, unsigned int count);
9
+#define ARRAY_SORT 1
10
+#include "common.c"
11
+
12
+#define min(a, b) ((a < b) ? (a) : (b))
13
+
14
+/*
15
+ * Implementation of merge sort:
16
+ */
17
+void array_sort(unsigned int **array, unsigned int count) {
18
+	unsigned int width, i, left_i, right_i, left_end, right_end, j;
19
+	unsigned int *current, *other, *swap;
20
+
21
+	/* Do nothing unless there are at least two items to sort: */
22
+	if (count < 2) return;
23
+
24
+	/* Although in-place (or more precisely, in-place-like) variants exist,
25
+	merge sort is not an in-place algorithm per se. */
26
+	current = *array;
27
+	/* Reserve enough space to copy the whole source array; indeed, merge sort's
28
+	worst case space complexity is O(n). */
29
+	other = malloc(sizeof(unsigned int) * count);
30
+
31
+	/* We start with an array of n sorted, 1-item arrays. */
32
+	for (width = 1; width < count; width *= 2) {
33
+		VERBOSE(1, "  Merging pairs of sorted, %u-item(s) arrays, \n", width);
34
+		for (i = 0; i < count; i += 2 * width) {
35
+			left_i    = i;
36
+			right_i   = min(left_i + width,      count - 1);
37
+			left_end  = min(left_i + width - 1,  count - 1);
38
+			right_end = min(right_i + width - 1, count - 1);
39
+			VERBOSE(2, "    Merging [%u-%u] and [%u-%u]\n", left_i, left_end, right_i, right_end);
40
+
41
+            /* Spare a few comparisons and assignments if there is only one item: */
42
+            if (left_i == right_end) {
43
+                VERBOSE(3, "      Simply copying [%u] here\n", left_i);
44
+                other[left_i] = current[left_i];
45
+                continue;
46
+            }
47
+
48
+            /* Do the same if there is actually only one pair: */
49
+            if (left_end == right_end) {
50
+                VERBOSE(3, "      Simply copying [%u-%u] here\n", left_i, left_end);
51
+                for (j = left_i; j <= left_end; ++ j) {
52
+                    other[j] = current[j];
53
+                }
54
+                continue;
55
+            }
56
+
57
+			for (j = left_i; j <= right_end; ++ j) {
58
+				if (left_i <= left_end && right_i <= right_end) {
59
+					/* There remain items on both sides: compare them: */
60
+					if (current[left_i] <= current[right_i]) {
61
+						other[j] = current[left_i];
62
+						++ left_i;
63
+					}
64
+					else {
65
+						other[j] = current[right_i];
66
+						++ right_i;
67
+					}
68
+				}
69
+				else if (left_i > left_end) {
70
+					/* There remain no more items on the left side: */
71
+					other[j] = current[right_i];
72
+					++ right_i;
73
+				}
74
+				else if (right_i > right_end) {
75
+					/* There remain no more items on the right side: */
76
+					other[j] = current[left_i];
77
+					++ left_i;
78
+				}
79
+			}
80
+		}
81
+		/* Swap the roles of our arrays: */
82
+		swap = current;
83
+		current = other;
84
+		other = swap;
85
+	}
86
+    *array = current;
87
+}