Memory: O(log2(max)*2)~O(1)
Speed: O(log2(max)*n)~O(n)
so i did before a MSD Radix Sort in place but i wanted to do one, with out the count, So i join together the quick sort and radix sort. Think as msd radix sort mod of 2.
Algorithm
i will explain this one directly with a table.
Code
start,finish,depth,mid are copy value because we can't modify because is a recursive funtion
s,f,mod_cal,auxiliar are static for fast calling and the memory usage
#pragma once
namespace leixor {
//fast log in power of 2 we are using size so we can't use bit_width
//is in excess on purpose
static size_t& logb2(size_t num) {
size_t aux = 1;
if (num == 0) return (aux = -1);
while (0 < (num >>= 1))
aux++;
return aux;
}
//------------------------obj version---------------------------
//custom get_max because i don't wanna add lib,and normaly we will use this in a custom class
template<class obj_arr>
static size_t& get_max(obj_arr*& arr, const size_t& size) {
size_t i = size%2, aux = arr[0].get_size_t(), aux2=-1;
if (size == 0)return aux2;
for (; i < size; i += 2) {
aux2 = arr[i].get_size_t();
aux = aux2 * (aux < aux2) + aux * (aux >= aux2);
aux2 = arr[i + 1].get_size_t();
aux = aux2 * (aux < aux2) + aux * (aux >= aux2);
//aux= (aux < aux2)?aux2:aux; are the same speed as the lane before
}
return aux;
}
//----------------------------pointer obj version---------------------
template<class obj_arr>
static size_t& get_max(obj_arr**& arr, const size_t& size) {
size_t i = size%2, aux = arr[0]->get_size_t(), aux2=-1;
if (size == 0)return aux2;
for (; i < size; i += 2) {
aux2 = arr[i]->get_size_t();
aux = aux2 * (aux < aux2) + aux * (aux >= aux2);
aux2 = arr[i + 1]->get_size_t();
aux = aux2 * (aux < aux2) + aux * (aux >= aux2);
}
return aux;
}
//---------------------------------------------------------------------
//-----------------object orientedversion---------
template<class obj_arr>
void two_rad(obj_arr*& arr, size_t start, size_t finish, size_t depth) {
depth--;
static size_t s, f;
static bool mod_cal;
static obj_arr auxiliar;
f = finish - 1; s = start;
while (s < f) {
auxiliar = arr[s];
if (mod_cal=(auxiliar.get_size_t() >> depth) % 2) {
arr[s] = arr[f];
arr[f] = auxiliar;
f--;
}
s+=!mod_cal;
}
size_t mid = s + !((arr[s].get_size_t() >> depth) % 2);
if (depth > 0) {
if (mid - start > 2)
two_rad(arr, start, mid, depth);
else if (mid - start > 1) {
mod_cal = arr[start].get_size_t() > arr[start + 1].get_size_t();
auxiliar = arr[start];
arr[start] = arr[start + mod_cal];
arr[start + mod_cal] = auxiliar;
}
if (finish - mid > 2)
two_rad(arr, mid, finish, depth);
else if (finish - mid > 1) {
mod_cal = arr[mid].get_size_t() > arr[mid + 1].get_size_t();
auxiliar = arr[mid];
arr[mid] = arr[mid + mod_cal];
arr[mid + mod_cal] = auxiliar;
}
}
}
template<class obj_arr>
bool qick_radix_sort(obj_arr* arr, size_t size) {
if (arr == nullptr || size < 2)
return false;
two_rad(arr, 0, size, logb2(get_max(arr, size)));
return true;
}
//-----------------pointer orientedversion---------
template<class obj_arr>
void two_rad(obj_arr**& arr, size_t start, size_t finish, size_t depth) {
depth--;
static size_t s, f;
static bool mod_cal;
static obj_arr* auxiliar;
f = finish - 1; s = start;
while (s < f) {
auxiliar = arr[s];
if (mod_cal=(auxiliar->get_size_t() >> depth) % 2) {
arr[s] = arr[f];
arr[f] = auxiliar;
f--;
}
s+=!mod_cal;
}
size_t mid =s+ !((arr[s]->get_size_t() >> depth)%2);
if (depth>0){
if (mid-start>2)
two_rad(arr,start,mid,depth);
else if (mid - start > 1) {
mod_cal = arr[start]->get_size_t() > arr[start + 1]->get_size_t();
auxiliar = arr[start];
arr[start] = arr[start + mod_cal];
arr[start + mod_cal] = auxiliar;
}
if (finish - mid > 2)
two_rad(arr,mid,finish,depth);
else if (finish - mid > 1) {
mod_cal = arr[mid]->get_size_t() > arr[mid + 1]->get_size_t();
auxiliar = arr[mid];
arr[mid] = arr[mid + mod_cal];
arr[mid + mod_cal] = auxiliar;
}
}
}
template<class obj_arr>
bool qick_radix_sort(obj_arr** arr, size_t size) {
if (arr == nullptr || size < 2)
return false;
two_rad(arr, 0, size, logb2(get_max(arr, size)));
return true;
}
}
needs
funtion inside a class as get_size_t return a size_t variable can be reference
and the calling of this sort is leixor::qick_radix_sort(arr, size);
ex:std::vector<D_CLASS> a; leixor::qick_radix_sort(a.data(), a.size());
Runtimes
the runtimes are in miliseconds, avarge of 100 times
optimization, new runtimes need it
/*
--------------------------------------------------
----------------object oriented version-----------
--------------------------------------------------
---------------------size pow 10------------------
--------------------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
--------------------------------------------------
max|1 |0.002613|0.020518|0.216481|2.23518|22.4944|222.093|2197.06
--------------------------------------------------
num|2 |0.003194|0.033248|0.31865|3.20488|31.2802|319.138|3135.21
--------------------------------------------------
pow|3 |0.003617|0.039951|0.383426|3.9421|39.9787|419.901|4099.95
--------------------------------------------------
2 |4 |0.003958|0.046783|0.478583|4.77747|47.9917|514.014|5001.75
--------------------------------------------------
|5 |0.003758|0.06327|0.604892|6.03168|58.432|579.918|5871.16
--------------------------------------------------
|6 |0.004298|0.064584|0.671869|6.92542|71.2283|703.449|6784.92
--------------------------------------------------
|7 |0.003727|0.062074|0.738229|7.47593|75.0941|752.692|7585.21
--------------------------------------------------
--------------------------------------------------
----------------pointer oriented version-----------
--------------------------------------------------
---------------------size pow 10------------------
--------------------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
--------------------------------------------------
max|1 |0.001209|0.006741|0.069374|0.888095|16.3528|186.809|1814.67
--------------------------------------------------
num|2 |0.001486|0.010471|0.107467|1.23582|27.598|312.24|3067.28
--------------------------------------------------
pow|3 |0.001785|0.014352|0.140364|1.69012|33.9956|428.07|4294.08
--------------------------------------------------
2 |4 |0.002111|0.018542|0.176611|2.13729|39.5618|549.902|5661.17
--------------------------------------------------
|5 |0.002112|0.022938|0.216402|2.51519|50.7784|683.679|7022.75
--------------------------------------------------
|6 |0.002354|0.027141|0.260751|2.9174|57.0826|795.653|8816.75
--------------------------------------------------
|7 |0.00232|0.030715|0.290544|3.32639|61.756|917.006|10731
--------------------------------------------------
*/
RunTime code
average of 100
#include "qick_radix_sort.h"
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <chrono>
#include<string>
#include <array>
#include <math.h>
#include <bitset>
class data
{
public:
data() {}
data(size_t& A):m(A) {};
size_t& get_size_t() { return m; };
void operator = (data& A) { m = A.m; };
void operator = (size_t& A) { m = A; };
size_t m;
};
void object_version(const size_t pow10, const size_t pow2) {
size_t size = pow(10, pow10);
data* arr = new data[size];
size_t mod = 1 << (2 + pow2);
float mediana = 0.0;
for (size_t i = 0; i < 100; i++)
{
for (size_t i = 0; i < size; i++) {
arr[i].m = rand() % mod;
}
auto started = std::chrono::high_resolution_clock::now();
leixor::qick_radix_sort(arr, size);
auto done = std::chrono::high_resolution_clock::now();
mediana += float(std::chrono::duration_cast<std::chrono::nanoseconds>(done - started).count()) / float(1000000);
}
std::cout << "|" << mediana /100;
delete[] arr;
};
void pointer_object_version(const size_t pow10, const size_t pow2) {
size_t size = pow(10, pow10);
data** arr = new data * [size];
size_t mod = 1 << (1+ pow2);
float mediana = 0.0;
for (size_t i = 0; i < size; i++)
arr[i] = new data();
for (size_t i = 0; i < 100; i++)
{
for (size_t i = 0; i < size; i++) {
arr[i]->m = rand() % mod;
}
auto started = std::chrono::high_resolution_clock::now();
leixor::qick_radix_sort(arr, size);
auto done = std::chrono::high_resolution_clock::now();
mediana += float(std::chrono::duration_cast<std::chrono::nanoseconds>(done - started).count()) / float(1000000);
}
std::cout << "|" << mediana / 100;
for (size_t i = 0; i < size; i++) {
delete arr[i];
}
delete[] arr;
};
int main() {
std::cout << "starting...\n";
std::array<std::string, 7> alfa = { "\nmax|1 ","\nnum|2 ","\npow|3 ","\n2 |4 ","\n |5 " ,"\n |6 " ,"\n |7 " };
std::cout <<
"\n --------------------------------------------------" <<
"\n ----------------object oriented version-----------" <<
"\n --------------------------------------------------\n\n";
std::cout <<
"\n ---------------------size pow 10------------------" <<
"\n --------------------------------------------------" <<
"\n | 1 | 2 | 3 | 4 | 5 | 6 | 7 |";
for (size_t z = 0; z < 7; z++) {
std::cout << "\n --------------------------------------------------" <<
alfa[z];
for (size_t i = 1; i < 8; i++) {
object_version(i, z);
}
}
std::cout << "\n --------------------------------------------------\n";
std::cout <<
"\n --------------------------------------------------" <<
"\n ----------------pointer oriented version-----------" <<
"\n --------------------------------------------------\n\n";
std::cout <<
"\n ---------------------size pow 10------------------" <<
"\n --------------------------------------------------" <<
"\n | 1 | 2 | 3 | 4 | 5 | 6 | 7 |";
for (size_t z = 0; z < 7; z++) {
std::cout << "\n --------------------------------------------------" <<
alfa[z];
for (size_t i = 1; i < 8; i++) {
pointer_object_version(i, z);
}
}
std::cout << "\n --------------------------------------------------\n";
}