First version of various versions of quicksort
This commit is contained in:
commit
6fd6dbfff3
13
data.inc
Normal file
13
data.inc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
int data[] = {
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
8, 7, 2, 1, 0, 9, 6,
|
||||||
|
};
|
4
makefile
Normal file
4
makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
release:
|
||||||
|
gcc qs.c -O2 -o qs && ./qs
|
||||||
|
debug:
|
||||||
|
gcc qs.c -g -o qs && gdb ./qs
|
64
qs.c
Normal file
64
qs.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// gcc qs.c -o qs && ./qs
|
||||||
|
// Basic tests for various quicksorts
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "qsort.h"
|
||||||
|
#include "zssort.h"
|
||||||
|
|
||||||
|
// function to print array elements
|
||||||
|
void printArray(int array[], int size) {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
printf("%d ", array[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// qs test function
|
||||||
|
void qs() {
|
||||||
|
#include "data.inc"
|
||||||
|
|
||||||
|
int n = sizeof(data) / sizeof(data[0]);
|
||||||
|
|
||||||
|
printf("(qs) Unsorted Array\n");
|
||||||
|
printArray(data, n);
|
||||||
|
|
||||||
|
// perform quicksort on data
|
||||||
|
quicksort(data, 0, n - 1);
|
||||||
|
|
||||||
|
printf("(qs) Sorted array in ascending order: \n");
|
||||||
|
printArray(data, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// qsr test function
|
||||||
|
void qsr() {
|
||||||
|
#include "data.inc"
|
||||||
|
|
||||||
|
int n = sizeof(data) / sizeof(data[0]);
|
||||||
|
|
||||||
|
// perform quicksort on data
|
||||||
|
rpivotstate state;
|
||||||
|
quicksort_rand(data, 0, n - 1, &state);
|
||||||
|
|
||||||
|
printf("(qsr) Sorted array in ascending order: \n");
|
||||||
|
printArray(data, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// qs test function
|
||||||
|
void zss() {
|
||||||
|
#include "data.inc"
|
||||||
|
|
||||||
|
int n = sizeof(data) / sizeof(data[0]);
|
||||||
|
|
||||||
|
// perform zssort on data
|
||||||
|
zssort(data, 0, n - 1);
|
||||||
|
|
||||||
|
printf("(zss) Sorted array in ascending order: \n");
|
||||||
|
printArray(data, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
qs();
|
||||||
|
qsr();
|
||||||
|
zss();
|
||||||
|
return 0;
|
||||||
|
}
|
132
qsort.h
Normal file
132
qsort.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/* Quick sort in C */
|
||||||
|
#ifndef MY_QUICKSORT_H
|
||||||
|
#define MY_QUICKSORT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Structure:
|
||||||
|
*
|
||||||
|
* - BASICS
|
||||||
|
* - EXTRAS
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* BASICS */
|
||||||
|
|
||||||
|
/** Swap operation */
|
||||||
|
static inline void swapit(uint32_t *a, uint32_t *b) {
|
||||||
|
uint32_t t = *a;
|
||||||
|
*a = *b;
|
||||||
|
*b = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partition the array and find the pivot element such that
|
||||||
|
*
|
||||||
|
* - Elements smaller than pivot are on left of pivot
|
||||||
|
* - Elements greater than pivot are on right of pivot
|
||||||
|
*
|
||||||
|
* @param array The array to partition
|
||||||
|
* @param low From when. (inclusive)
|
||||||
|
* @param high Until when. (inclusive too!)
|
||||||
|
*/
|
||||||
|
static inline int partition(uint32_t array[], int low, int high) {
|
||||||
|
/* This is "Lomuto"s unidirectional partitioner - see algorithms book */
|
||||||
|
|
||||||
|
/* select the rightmost element as pivot */
|
||||||
|
uint32_t pivot = array[high];
|
||||||
|
|
||||||
|
/* index until smaller or eq elements lay */
|
||||||
|
int i = (low - 1);
|
||||||
|
|
||||||
|
/* traverse each element of the array */
|
||||||
|
/* compare them with the pivot */
|
||||||
|
#pragma GCC unroll 4
|
||||||
|
for (int j = low; j < high; ++j) {
|
||||||
|
if (array[j] <= pivot) {
|
||||||
|
|
||||||
|
/* if element smaller than pivot is found */
|
||||||
|
/* swap it with the greater element pointed by i */
|
||||||
|
++i;
|
||||||
|
|
||||||
|
/* swap element at i with element at j */
|
||||||
|
swapit(&array[i], &array[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* swap the pivot element with the greater element at i */
|
||||||
|
swapit(&array[i + 1], &array[high]);
|
||||||
|
|
||||||
|
/* return the partition point */
|
||||||
|
return (i + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Simple in-place recursive quicksort on array for elements in [low, high) indices */
|
||||||
|
static inline void quicksort(uint32_t array[], int low, int high) {
|
||||||
|
if (low < high) {
|
||||||
|
int pi = partition(array, low, high);
|
||||||
|
|
||||||
|
/* recursive call on the left of pivot */
|
||||||
|
quicksort(array, low, pi - 1);
|
||||||
|
|
||||||
|
/* recursive call on the right of pivot */
|
||||||
|
quicksort(array, pi + 1, high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* EXTRAS */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Partition the array and using the pivot index
|
||||||
|
*
|
||||||
|
* - Elements smaller than pivot are on left of pivot
|
||||||
|
* - Elements greater than pivot are on right of pivot
|
||||||
|
*
|
||||||
|
* @param array The array to partition
|
||||||
|
* @param pi The index of the pivot element to use. 0 or high is what OG quicksorts do.
|
||||||
|
* @param low From when. (inclusive)
|
||||||
|
* @param high Until when. (inclusive too!)
|
||||||
|
*/
|
||||||
|
static inline int partition_with_pivot(uint32_t array[], int pi, int low, int high) {
|
||||||
|
/*
|
||||||
|
* Rem.: This looks like overhead,
|
||||||
|
* but after seriously considering
|
||||||
|
* writing the whole out I can tell
|
||||||
|
* this is still fastests basically.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* swap pivot with rightmost */
|
||||||
|
swapit(&array[high], &array[pi]);
|
||||||
|
/* delegate to previous sol. */
|
||||||
|
return partition(array, low, high);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 32-bit LCG for fast random generations
|
||||||
|
static inline uint32_t lcg(uint32_t *state) {
|
||||||
|
*state = *state * 1664525u + 1013904223u;
|
||||||
|
return *state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get pivot index in [0, len-1] without modulus - see our fastrand.h */
|
||||||
|
static inline uint32_t pick_pivot(uint32_t *state, uint32_t len) {
|
||||||
|
uint32_t rand = lcg(state);
|
||||||
|
/* Multiply by len, take the upper 32 bits of the 64-bit result */
|
||||||
|
return (uint32_t)(((uint64_t)rand * len) >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef uint32_t rpivotstate;
|
||||||
|
|
||||||
|
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
|
||||||
|
static inline void quicksort_rand(uint32_t array[], int low, int high, rpivotstate *state) {
|
||||||
|
if (low < high) {
|
||||||
|
int pi = pick_pivot(state, (high + 1) - low) + low;
|
||||||
|
pi = partition_with_pivot(array, pi, low, high);
|
||||||
|
|
||||||
|
/* recursive call on the left of pivot */
|
||||||
|
quicksort_rand(array, low, pi - 1, state);
|
||||||
|
|
||||||
|
/* recursive call on the right of pivot */
|
||||||
|
quicksort_rand(array, pi + 1, high, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MY_QUICKSORT_H */
|
53
zssort.h
Normal file
53
zssort.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef ZS_SORT_H
|
||||||
|
#define ZS_SORT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "qsort.h"
|
||||||
|
|
||||||
|
static inline void zssort(uint32_t array[], int low, int high) {
|
||||||
|
/* (*) Loop handles original "other half recursion"! */
|
||||||
|
while(low < high) {
|
||||||
|
int pi = partition(array, low, high);
|
||||||
|
|
||||||
|
/* If we recurse only the smaller part */
|
||||||
|
/* That ensures at most n/2 elements can */
|
||||||
|
/* be on any given level of the recursion */
|
||||||
|
/* tree: that is we ensure log2(N) memuse! */
|
||||||
|
if((pi - low) < (high - pi)) {
|
||||||
|
// Left smaller: recurse left of pivot
|
||||||
|
zssort(array, low, pi - 1);
|
||||||
|
// (*) Update partitioning loop for remaining part
|
||||||
|
low = pi + 1;
|
||||||
|
} else {
|
||||||
|
// Right smaller: recurse right of pivot
|
||||||
|
zssort(array, pi + 1, high);
|
||||||
|
// (*) Update partitioning loop for remaining part
|
||||||
|
high = pi - 1; /* high inclusive! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void zssort_rand(uint32_t array[], int low, int high, rpivotstate *state) {
|
||||||
|
while (low < high) {
|
||||||
|
int pi = pick_pivot(state, (high + 1) - low) + low;
|
||||||
|
|
||||||
|
pi = partition_with_pivot(array, pi, low, high);
|
||||||
|
/* If we recurse only the smaller part */
|
||||||
|
/* That ensures at most n/2 elements can */
|
||||||
|
/* be on any given level of the recursion */
|
||||||
|
/* tree: that is we ensure log2(N) memuse! */
|
||||||
|
if((pi - low) < (high - pi)) {
|
||||||
|
// Left smaller: recurse left of pivot
|
||||||
|
zssort_rand(array, low, pi - 1, state);
|
||||||
|
// (*) Update partitioning loop for remaining part
|
||||||
|
low = pi + 1;
|
||||||
|
} else {
|
||||||
|
// Right smaller: recurse right of pivot
|
||||||
|
zssort_rand(array, pi + 1, high, state);
|
||||||
|
// (*) Update partitioning loop for remaining part
|
||||||
|
high = pi - 1; /* high inclusive! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ZS_SORT_H */
|
Loading…
x
Reference in New Issue
Block a user