aboutsummaryrefslogtreecommitdiff
path: root/src/quicksort.c
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2022-04-09 09:43:53 +0200
committerThomas Schmucker <ts@its1.de>2022-04-09 09:43:53 +0200
commit154874afda4a8df885e51c01f7681f04fb0b8e61 (patch)
tree274817eb2793584b0e3d856de5504a614f2b4e89 /src/quicksort.c
parent2863f4f1d2a6a6a8704454824d6c291d2e0d4b5c (diff)
downloaddata-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.tar.gz
data-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.tar.bz2
data-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.zip
neue Verzeichnisstruktur
Diffstat (limited to 'src/quicksort.c')
-rw-r--r--src/quicksort.c684
1 files changed, 684 insertions, 0 deletions
diff --git a/src/quicksort.c b/src/quicksort.c
new file mode 100644
index 0000000..4657dcd
--- /dev/null
+++ b/src/quicksort.c
@@ -0,0 +1,684 @@
1#include <assert.h>
2#include <stdio.h>
3#include <stdlib.h>
4#include <time.h>
5
6#include "util.h"
7
8static int
9bigrand(void)
10{
11 int x = (rand() << 24) | (rand() << 16) | (rand() << 8) | rand();
12 if ( x < 0 )
13 return -x;
14 return x;
15}
16
17static int
18randint(int l, int u)
19{
20 return l + bigrand() % (u - l + 1);
21}
22
23typedef int T;
24
25static const int CUTOFF = 128;
26
27static inline void
28swap(T a[], int i, int j)
29{
30 T t = a[i];
31 a[i] = a[j];
32 a[j] = t;
33}
34
35static void
36insertsort(T a[], int n)
37{
38 int i, j;
39 for ( i = 1; i < n; ++i ) {
40 T t = a[i];
41 for ( j = i; j > 0 && a[j - 1] > t; --j )
42 a[j] = a[j - 1];
43 a[j] = t;
44 }
45}
46
47static void
48quicksort(T a[], int n)
49{
50 int i, last;
51
52 if ( n <= CUTOFF )
53 return;
54
55 swap(a, 0, bigrand() % n);
56
57 last = 0;
58 for ( i = 1; i < n; ++i )
59 if ( a[i] < a[0] )
60 swap(a, ++last, i);
61
62 swap(a, 0, last);
63
64 quicksort(a, last);
65 quicksort(a + last + 1, n - last - 1);
66}
67
68void
69my_quicksort(T a[], int n)
70{
71 quicksort(a, n);
72 insertsort(a, n);
73}
74
75static int
76cmp(const void *a, const void *b)
77{
78 const int *pa = (const T *) a;
79 const int *pb = (const T *) b;
80
81 if ( *pa < *pb )
82 return -1;
83 if ( *pa > *pb )
84 return 1;
85 return 0;
86}
87
88void
89c_quicksort(T a[], int n)
90{
91 assert(n >= 0);
92 qsort(a, (size_t) n, sizeof(T), cmp);
93}
94
95/* This function takes last element as pivot, places
96 the pivot element at its correct position in sorted
97 array, and places all smaller (smaller than pivot)
98 to left of pivot and all greater elements to right
99 of pivot */
100int
101partition(int arr[], int low, int high)
102{
103 int pivot = arr[high]; // pivot
104 int i = (low - 1); // Index of smaller element
105
106 for ( int j = low; j <= high - 1; j++ ) {
107 // If current element is smaller than or
108 // equal to pivot
109 if ( arr[j] <= pivot ) {
110 i++; // increment index of smaller element
111 swap(arr, i, j);
112 }
113 }
114 swap(arr, i + 1, high);
115 return (i + 1);
116}
117
118/* The main function that implements QuickSort
119 arr[] --> Array to be sorted,
120 low --> Starting index,
121 high --> Ending index */
122void
123quickSort(int arr[], int low, int high)
124{
125 while ( low < high ) {
126 /* pi is partitioning index, arr[p] is now
127 at right place */
128 int pi = partition(arr, low, high);
129
130 if ( pi - low < high - pi ) {
131 quickSort(arr, low, pi - 1);
132 low = pi + 1;
133 }
134 else {
135 quickSort(arr, pi + 1, high);
136 high = pi - 1;
137 }
138 }
139}
140
141void
142g4g_quicksort(T a[], int n)
143{
144 quickSort(a, 0, n - 1);
145}
146
147static void
148three_way_quicksort(int a[], int l, int r)
149{
150 int k;
151 T v = a[r];
152
153 if ( r <= l )
154 return;
155
156 int i = l - 1, j = r, p = l - 1, q = r;
157
158 for ( ;; ) {
159 while ( a[++i] < v )
160 ;
161 while ( v < a[--j] )
162 if ( j == l )
163 break;
164 if ( i >= j )
165 break;
166
167 swap(a, i, j);
168
169 if ( a[i] == v )
170 swap(a, ++p, i);
171 if ( v == a[j] )
172 swap(a, --q, j);
173 }
174 swap(a, i, r);
175 j = i - 1;
176 i = i + 1;
177
178 for ( k = l; k <= p; ++k, --j )
179 swap(a, k, j);
180 for ( k = r - 1; k >= q; --k, ++i )
181 swap(a, k, i);
182
183 three_way_quicksort(a, l, j);
184 three_way_quicksort(a, i, r);
185}
186
187void
188sed_quicksort(int a[], int n)
189{
190 three_way_quicksort(a, 0, n - 1);
191}
192
193/* ====================== HEAPSORT ======================= */
194
195#define LEFT(idx) (idx * 2 + 1)
196#define RIGHT(idx) (idx * 2 + 2)
197#define PARENT(idx) ((idx - 1) / 2)
198
199static void
200fixdown(T heap[], int i, int n)
201{
202 for ( ;; ) {
203 const int l = LEFT(i);
204 const int r = RIGHT(i);
205 int m = i;
206
207 if ( l < n && heap[m] < heap[l] )
208 m = l;
209
210 if ( r < n && heap[m] < heap[r] )
211 m = r;
212
213 if ( m == i )
214 break;
215
216 swap(heap, m, i);
217
218 i = m;
219 }
220}
221
222static void
223heapify(T heap[], int n)
224{
225 for ( int i = n / 2 - 1; i >= 0; --i )
226 fixdown(heap, i, n);
227}
228
229void
230my_heapsort(T a[], int n)
231{
232 heapify(a, n);
233
234 for ( int i = n - 1; i >= 0; --i ) {
235 swap(a, 0, i);
236 fixdown(a, 0, i);
237 }
238}
239
240void
241heapsort_bu(T *data, int n) // zu sortierendes Feld und seine Länge
242{
243 T val;
244 int parent, child;
245 int root = n >> 1; // erstes Blatt im Baum
246 int count = 0; // Zähler für Anzahl der Vergleiche
247
248 for ( ;; ) {
249 if ( root ) { // Teil 1: Konstruktion des Heaps
250 parent = --root;
251 val = data[root]; // zu versickernder Wert
252 }
253 else if ( --n ) { // Teil 2: eigentliche Sortierung
254 val = data[n]; // zu versickernder Wert vom Heap-Ende
255 data[n] = data[0]; // Spitze des Heaps hinter den Heap in
256 parent = 0; // den sortierten Bereich verschieben
257 }
258 else // Heap ist leer; Sortierung beendet
259 break;
260
261 while ( (child = (parent + 1) << 1) < n ) // zweites (!) Kind;
262 { // Abbruch am Ende des Heaps
263 if ( ++count, data[child - 1] > data[child] ) // größeres Kind wählen
264 --child;
265
266 data[parent] = data[child]; // größeres Kind nach oben rücken
267 parent = child; // in der Ebene darunter weitersuchen
268 }
269
270 if ( child == n ) // ein einzelnes Kind am Heap-Ende
271 { // ist ĂĽbersprungen worden
272 if ( ++count, data[--child] >= val ) { // größer als der zu versick-
273 data[parent] = data[child]; // ernde Wert, also noch nach oben
274 data[child] = val; // versickerten Wert eintragen
275 continue;
276 }
277
278 child = parent; // 1 Ebene nach oben zurĂĽck
279 }
280 else {
281 if ( ++count, data[parent] >= val ) { // das Blatt ist größer als der
282 data[parent] = val; // zu versickernde Wert, der damit
283 continue; // direkt eingetragen werden kann
284 }
285
286 child = (parent - 1) >> 1; // 2 Ebenen nach oben zurĂĽck
287 }
288
289 while ( child != root ) // maximal zum Ausgangspunkt zurĂĽck
290 {
291 parent = (child - 1) >> 1; // den Vergleichswert haben wir bereits
292 // nach oben verschoben
293 if ( ++count, data[parent] >= val ) // größer als der zu versickernde
294 break; // Wert, also Position gefunden
295
296 data[child] = data[parent]; // Rückverschiebung nötig
297 child = parent; // 1 Ebene nach oben zurĂĽck
298 }
299
300 data[child] = val; // versickerten Wert eintragen
301 }
302}
303
304/*----------------------------------------------------------------------*/
305/* BOTTOM-UP HEAPSORT */
306/* Written by J. Teuhola <teuhola@cs.utu.fi>; the original idea is */
307/* probably due to R.W. Floyd. Thereafter it has been used by many */
308/* authors, among others S. Carlsson and I. Wegener. Building the heap */
309/* bottom-up is also due to R. W. Floyd: Treesort 3 (Algorithm 245), */
310/* Communications of the ACM 7, p. 701, 1964. */
311/*----------------------------------------------------------------------*/
312
313#define element float
314
315/*-----------------------------------------------------------------------*/
316/* The sift-up procedure sinks a hole from v[i] to leaf and then sifts */
317/* the original v[i] element from the leaf level up. This is the main */
318/* idea of bottom-up heapsort. */
319/*-----------------------------------------------------------------------*/
320static void
321siftup(T v[], int i, int n)
322{
323 int j, start;
324 T x;
325
326 start = i;
327 x = v[i];
328 j = i << 1;
329 while ( j <= n ) {
330 if ( j < n )
331 if ( v[j] < v[j + 1] )
332 j++;
333 v[i] = v[j];
334 i = j;
335 j = i << 1;
336 }
337 j = i >> 1;
338 while ( j >= start ) {
339 if ( v[j] < x ) {
340 v[i] = v[j];
341 i = j;
342 j = i >> 1;
343 }
344 else
345 break;
346 }
347 v[i] = x;
348} /* End of siftup */
349
350/*----------------------------------------------------------------------*/
351/* The heapsort procedure; the original array is r[0..n-1], but here */
352/* it is shifted to vector v[1..n], for convenience. */
353/*----------------------------------------------------------------------*/
354void
355bottom_up_heapsort(T r[], int n)
356{
357 int k;
358 T x;
359 T * v;
360
361 v = r - 1; /* The address shift */
362
363 /* Build the heap bottom-up, using siftup. */
364 for ( k = n >> 1; k > 1; k-- )
365 siftup(v, k, n);
366
367 /* The main loop of sorting follows. The root is swapped with the last */
368 /* leaf after each sift-up. */
369 for ( k = n; k > 1; k-- ) {
370 siftup(v, 1, k);
371 x = v[k];
372 v[k] = v[1];
373 v[1] = x;
374 }
375} /* End of bottom_up_heapsort */
376
377/* ====================== HEAPSORT ======================= */
378
379/* ====================== INTROSORT ======================= */
380
381static void
382introsort(T a[], int n, int h)
383{
384 int i, last;
385
386 if ( n <= CUTOFF )
387 return;
388
389 if ( --h == 1 ) {
390 my_heapsort(a, n);
391 return;
392 }
393
394 swap(a, 0, bigrand() % n);
395
396 last = 0;
397 for ( i = 1; i < n; ++i )
398 if ( a[i] < a[0] )
399 swap(a, ++last, i);
400
401 swap(a, 0, last);
402
403 introsort(a, last, h);
404 introsort(a + last + 1, n - last - 1, h);
405}
406
407void
408my_introsort(T a[], int n)
409{
410 int h = 1;
411
412 for ( int nn = 1; nn < n; nn <<= 1 )
413 ++h;
414
415 introsort(a, n, h);
416 insertsort(a, n);
417}
418
419static void
420pp_quicksort_impl(T a[], int l, int u)
421{
422 if ( u - l < CUTOFF )
423 return;
424
425 swap(a, l, randint(l, u));
426
427 T t = a[l];
428 int i = l;
429 int j = u + 1;
430 for ( ;; ) {
431 do
432 i++;
433 while ( /*i <= u &&*/ a[i] < t );
434 do
435 j--;
436 while ( a[j] > t );
437 if ( i > j )
438 break;
439 swap(a, i, j);
440 }
441 swap(a, l, j);
442 pp_quicksort_impl(a, l, j - 1);
443 pp_quicksort_impl(a, j + 1, u);
444}
445
446void
447pp_quicksort(T a[], int n)
448{
449 pp_quicksort_impl(a, 0, n - 1);
450 insertsort(a, n);
451}
452
453static void
454pp_quicksort_impl_it(T a[], int l, int u, int h)
455{
456 if ( --h == 1 ) {
457 my_heapsort(a + l, u - l + 1);
458 return;
459 }
460
461 while ( u - l >= CUTOFF ) {
462 swap(a, l, randint(l, u));
463
464 T t = a[l];
465 int i = l;
466 int j = u + 1;
467
468 for ( ;; ) {
469 do
470 i++;
471 while ( /*i <= u && */ a[i] < t );
472 do
473 j--;
474 while ( a[j] > t );
475 if ( i > j )
476 break;
477 swap(a, i, j);
478 }
479 swap(a, l, j);
480
481 if ( j - l < u - j ) {
482 pp_quicksort_impl_it(a, l, j - 1, h);
483 l = j + 1;
484 }
485 else {
486 pp_quicksort_impl_it(a, j + 1, u, h);
487 u = j - 1;
488 }
489 }
490}
491
492void
493pp_quicksort_it(T a[], int n)
494{
495 int h = 1;
496
497 for ( int nn = 1; nn < n; nn <<= 1 )
498 ++h;
499
500 pp_quicksort_impl_it(a, 0, n - 1, h);
501 insertsort(a, n);
502}
503
504int
505binary_search(T x, T v[], int n)
506{
507 int low, high;
508
509 low = 0;
510 high = n - 1;
511 while ( low <= high ) {
512 int mid = low + ((high - low) / 2);
513 if ( x > v[mid] )
514 low = mid + 1;
515 else if ( x < v[mid] )
516 high = mid - 1;
517 else
518 return mid;
519 }
520 return -1;
521}
522
523int
524lower_bound(T x, T v[], int n)
525{
526 int low, high;
527
528 low = 0;
529 high = n;
530 while ( low < high ) {
531 int mid = low + ((high - low) / 2);
532
533 if ( x > v[mid] )
534 low = mid + 1;
535 else
536 high = mid;
537 }
538 return x == v[low] ? low : -1;
539}
540
541int
542upper_bound(T x, T v[], int n)
543{
544 int low, high;
545
546 low = 0;
547 high = n;
548 while ( low < high ) {
549 int mid = low + ((high - low) / 2);
550
551 if ( x >= v[mid] )
552 low = mid + 1;
553 else
554 high = mid;
555 }
556 return (low > 0 && x == v[low - 1]) ? low - 1 : -1;
557}
558
559/* TESTTREIBER */
560
561void
562gen_testset_random(T a[], int n)
563{
564 for ( int i = 0; i < n; ++i )
565 a[i] = bigrand();
566}
567
568void
569gen_testset_random2(T a[], int n)
570{
571 for ( int i = 0; i < n; ++i )
572 a[i] = bigrand() % 100;
573}
574
575void
576gen_testset_asc(T a[], int n)
577{
578 for ( int i = 0; i < n; ++i )
579 a[i] = i;
580}
581
582void
583gen_testset_desc(T a[], int n)
584{
585 for ( int i = n; i >= 0; --i )
586 a[i] = i;
587}
588
589void
590gen_testset_unique(T a[], int n)
591{
592 for ( int i = 0; i < n; ++i )
593 a[i] = 1;
594}
595
596void
597test_sorting(T a[], int n)
598{
599 for ( int i = 1; i < n; ++i )
600 if ( a[i - 1] > a[i] ) {
601 puts("Fehler!");
602 exit(EXIT_SUCCESS);
603 }
604}
605
606void
607do_one_test(int n, void (*do_sort)(T a[], int n), void (*gen_testset)(T a[], int n))
608{
609 T * a;
610 clock_t start, ende;
611
612 a = malloc(sizeof(T) * (size_t) n);
613
614 (*gen_testset)(a, n);
615
616 start = clock();
617 (*do_sort)(a, n);
618 ende = clock();
619
620 test_sorting(a, n);
621
622 free(a);
623
624 printf("%10.3lf sec", ((double) ende - start) / CLOCKS_PER_SEC);
625 fflush(stdout);
626}
627
628void
629do_all_tests(const char *msg, int n, void (*do_sort)(T a[], int n))
630{
631 printf("%-15.15s n=%-10d: ", msg, n);
632 do_one_test(n, do_sort, gen_testset_random);
633 do_one_test(n, do_sort, gen_testset_random2);
634 do_one_test(n, do_sort, gen_testset_asc);
635 do_one_test(n, do_sort, gen_testset_desc);
636 do_one_test(n, do_sort, gen_testset_unique);
637 putchar('\n');
638}
639
640/* ENDE TESTTREIBER */
641
642int
643main(void)
644{
645 const int n = 20000000;
646
647 srand(time(0));
648 do_all_tests("my_heapsort", n, my_heapsort);
649 do_all_tests("heapsort_bu", n, heapsort_bu);
650 do_all_tests("bottom_up_heapsort", n, bottom_up_heapsort);
651 do_all_tests("c_quicksort", n, c_quicksort);
652 //do_all_tests("g4g_quicksort", n, g4g_quicksort);
653 //do_all_tests("sed_quicksort", n, sed_quicksort);
654 do_all_tests("my_introsort", n, my_introsort);
655 //do_all_tests("my_quicksort", n, my_quicksort);
656 do_all_tests("pp_quicksort", n, pp_quicksort);
657 do_all_tests("pp_quicksort_it", n, pp_quicksort_it);
658
659 return 0;
660}
661
662#if 0
663int _main(void)
664{
665 T array[20];
666
667 for ( int i = 0; i != NELEM(array); ++i )
668 array[i] = rand() % 10;
669
670 sort(array, NELEM(array));
671 print(array, NELEM(array));
672
673 int value;
674 while ( scanf("%d", &value) == 1 && value != -1 ) {
675 int bs = binary_search(value, array, NELEM(array));
676 int lb = lower_bound(value, array, NELEM(array));
677 int ub = upper_bound(value, array, NELEM(array));
678
679 printf("bs: %d - lb: %d - ub: %d\n", bs, lb, ub);
680 }
681
682 return EXIT_SUCCESS;
683}
684#endif