myqsort/qsort.h
2025-04-05 02:15:39 +02:00

133 lines
3.5 KiB
C

/* 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 */