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