[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH v2] lib: echtes QuickSort



* lib/qsort: GnomeSort durch echten QuickSort-Algorithmus ersetzt.

Signed-off-by: Andreas Freimuth <m.nemo@xxxxxxx>
---
 src/lib/sort.c |   72 ++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/src/lib/sort.c b/src/lib/sort.c
index 8717c96..e457db4 100644
--- a/src/lib/sort.c
+++ b/src/lib/sort.c
@@ -29,30 +29,62 @@
 #include <stdlib.h>
 #include <string.h>
 
-void qsort(void *base, size_t num, size_t size, int (*comparator)(const void *, const void *))
+static void swap(void* a, void* b, size_t size)
 {
-    //FIXME
-    //Die Funktion heißt Qsort... Gnomesort tuts zwar meistens auch, ist aber
-    //nicht Sinn der Sache, außerdem bin ich grad zu müde für sowas :p
-    unsigned char _tmp[size];
-    void* tmp = _tmp;
-    int i = 0;
-
-    if (num == 0) {
+    if(a == b) {
         return;
     }
 
-    while (i < (num - 1)) {
-        if (comparator(base + i * size, base + (i + 1) * size) > 0) {
-            memcpy(tmp, base + i * size, size);
-            memcpy(base + i * size, base + (i + 1) * size, size);
-            memcpy(base + (i + 1) * size, tmp, size);
-            
-            if (i > 0) {
-                i--;
-            }
-        } else {
-            i++;
+    char temp[size];
+    memcpy(temp, a, size);
+    memcpy(a, b, size);
+    memcpy(b, temp, size);
+}
+
+void qsort(void* base, size_t num, size_t size, int (*comparator)(const void*, const void*))
+{
+    if(num < 2) {
+        return;
+    }
+
+    size_t left = 1, right = num - 1;
+
+    /*
+     * Als Pivot-Element p ist das Element mit Index 0 gewählt. Das Array wird
+     * grob vorsortiert indem alles was kleiner p ist nach links und alles was
+     * größer oder gleich p ist nach rechts gebracht wird.
+     */
+    while(left <= right) {
+        while((left <= right) && (comparator(base, base + left * size) > 0)) {
+            ++left;
+        }
+
+        while((left < right) && (comparator(base, base + right * size) <= 0)) {
+            --right;
+        }
+
+        if(left >= right) {
+            break;
         }
+
+        swap(base + left * size, base + right * size, size);
+        ++left; --right;
     }
+
+    /*
+     * Hier angekommen zeigt left auf das erste Element, welches nicht kleiner
+     * ist als das Pivot-Element. left soll aber auf das letzte Element zeigen
+     * das kleiner ist als das Pivot-Element. right könnte auf dieses zeigen,
+     * soll aber auf das erste nicht kleiner Element zeigen.
+     */
+    right = left--;
+
+    /* Pivot-Element einsortieren */
+    swap(base, base + left * size, size);
+
+    /* Linke Seite sortieren. */
+    qsort(base, left, size, comparator);
+    /* Rechte Seite sortieren. */
+    qsort(base + right * size, num - right, size, comparator);
 }
+
-- 
1.7.6.2