52 lines
1.4 KiB
C
52 lines
1.4 KiB
C
|
|
/**
|
||
|
|
* Sort algorithm for nearly-sorted data.
|
||
|
|
*
|
||
|
|
* Runtime:
|
||
|
|
* - Worst case O(n^2) [smallrange / descending]
|
||
|
|
* - random case O(nlogn)
|
||
|
|
* Space: same as runtime
|
||
|
|
*/
|
||
|
|
#include <vector> // can do with malloc only if needed but this spares more ram. Also can do with a stack data type..
|
||
|
|
#include <cstdint> // uint32_t
|
||
|
|
|
||
|
|
// TODO: outliersort(...) function with parametrizable "what is an outlier?" and "init" functions!
|
||
|
|
// why? Because when I renamed outnsi to outlier I realized the only rule is to keep the begin
|
||
|
|
// of the array sorted but otherwise we better put into the outlier data that would make us
|
||
|
|
// less likely to be able to fill-in more data points (think of real outliers like [1 9000 2 3 4 ...8999]
|
||
|
|
|
||
|
|
// TODO: simple to make this work with custom comparator and type..
|
||
|
|
void nsort(uint32_t *arr, int n) {
|
||
|
|
// Temp space - worst case O(n) size
|
||
|
|
std::vector<uint32_t> outlier;
|
||
|
|
|
||
|
|
// Split [i: read, j: write]
|
||
|
|
uint32_t max = (n > 0) ? arr[0] : 0;
|
||
|
|
uint32_t i = 1;
|
||
|
|
uint32_t j = 1;
|
||
|
|
|
||
|
|
while(i < n) {
|
||
|
|
if(arr[i] < max) {
|
||
|
|
outlier.push_back(arr[i++]);
|
||
|
|
} else if(i > j) {
|
||
|
|
arr[j++] = arr[i++];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(outlier.size() > 1) {
|
||
|
|
// Recursion
|
||
|
|
nsort(&outlier[0], outlier.size());
|
||
|
|
|
||
|
|
// Merge-from-right [j: sorted right-index, i: write index]
|
||
|
|
uint32_t k = outlier.size() - 1;
|
||
|
|
--j;
|
||
|
|
--i;
|
||
|
|
while(i >= 0) {
|
||
|
|
if(outlier[k] > arr[j]) {
|
||
|
|
arr[i--] = outlier[k--];
|
||
|
|
} else {
|
||
|
|
arr[i--] = arr[j--];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|