您的位置:首页 > 编程语言 > C语言/C++

C++基数排序另一种实现

2017-02-04 13:45 330 查看

Intro

这个版本的基数排序和算法导论的不太相同,思想都是一样的,但是感觉比那个好理解很多

选用unsigned int 也就是u32 作为例子,按位来,一共只有两个桶,所以要比32次。但其实基数排序非常有意思。

在于这些都是可变的

设待排序列为n个记录,d个关键码,关键码的取值范围为radix,排序时间复杂度为O(d(n+radix)),

空间复杂度2n

这里n ∈[1e6,1e9) 做了下测试,d=32(因为32bit) ,radix = 2

思路一共两条,最高位优先MSD和最低位优先LSD,都是按位分桶嘛,也就是一个从头往尾排,一个从尾往头排。两个都可以,但是MSD会有点麻烦,比完高位要是一样还得再比一下低位,要分出很多子序列。而且并没有感受到有什么特别的优点,所以就LSD了

算法流程

先设一个tmp数组,也就是桶。但是因为按位来,0和1可以是一个大桶里的两个小桶

从最低位开始,0放一桶,1放一桶,0从tmp的第0位开始装,1从最后一位装。

装完合并回data,但是注意1那个桶的顺序要弄正常一点,之前是倒着装的。

合并的时候就是0放前1放后,这样最后是升序的

讨论

编程

这个之前学排序都是用泛型写的,基数排序不是很容易泛型。如果不是unsigned , 就要对符号位单独处理。如果是浮点类型,也可以用基数排序!!!之前被人怼了,当时没学IEEE浮点标准。肯定要对尾数和阶码作特殊处理,我懒得搞了网上有论文。

但是这说明一个道理!如果想兼容之前的排序代码,就要用模板特化

template<typename T>
void radixSort(T* data,int left,int right){}

template<> void radixSort<u32>(u32* data,int left, int right)
{
//implement
}


也就是说,对不同的typename都应该分别实现不同的方法,调用的时候会调用对应的函数。

时间复杂度与空间复杂度

O(d(n+radix))这个在intro里面提了一下,可以稍微简化一下看一下效果,忽略太小的:

O(d*n) 看着是线性的,d一般不会太大,这里的例子是32,但是快排nlgn的lgn不一定就比d大。这样分析的话,数组长度要大于1<<32之后才会看到效果。

但是,基数排序是一个比较容易并行的排序,并行之后还可以大概除一个常数(代码要写的非常好才可以把大概去掉)这就可能会比快排好啦。

实验

就是vanilla quick sort 和radix sort比。

#数组长度1e7
quick sort 1.04497
radix sort 1.65082

#数组长度1e8
quick sort 11.9672
radix sort 16.6019

#数组长度1e9
quick sort 133.076
# 爆内存啦


为什么会爆内存呢?u32是4byte,1e9个u32也就是4GB!空间复杂度2N刚好我内存是8GB。然后就只能重启了= =

这样的话是不如快排快的,改进思路就是换基数和CUDA并行

主要代码

template<typename T>
void radixSort(T* data,int left,int right){}

template<> void radixSort<u32>(u32* data,int left, int right)
{
const int len = right - left + 1;
u32* tmp = new u32[len];
for(u32 bit = 0;bit < 32;bit++)
{

u32 cnt0 = 0;
u32 cnt1 = 0;

for(u32 i = 0;i < len;i++)
{
const u32 d = data[i];
const u32 bit_mask = (1<<bit);

if(d & bit_mask)
tmp[cnt1++] = d;
else
tmp[len - cnt0++ - 1] = d;
}

for(u32 i = 0;i < cnt0;i++)
data[i] = tmp[len - i -1];
for(u32 i = 0;cnt0 < len;i++)
data[cnt0++] = tmp[i];
}
delete[] tmp;
}


全部代码

#include<thread>
#include<atomic>
#include<ctime>
#include<iostream>
#include<ctime>
#include<cstdlib>
#include<algorithm>
using namespace std;

using u32 = unsigned int;
using TYPE = u32;
const int LEN =(int)1e6;

template<typename T=int>
void disp(T* data,int l)
{
// cout<<__func__<<": ";
for(int i = 0;i<l;i++)
{
if((i!=0) && (i%10==0))
cout<<endl;
cout<<data[i]<<" ";
}
cout<<endl;
}
template<typename T=int>
void init(T* data,int len)
{
srand(unsigned(time(0)));
for(int i = 0;i<len;i++)
data[i] = (T)rand();
}
template<typename T=int>
void bubbleSort(T* data,int left = 0,int right = LEN-1)
{
for(int i = left; i <= right; i++)
for (int j = i + 1; j <= right; j++)
if (data[i] > data[j])
swap(data[i], data[j]);
}
template<typename T=int>
void qsort(T* data,int left = 0,int right = LEN-1)
{
if(left < right)
{
int l = left;
int h = right;
T pivot = data[left];
while(l<h)
{
while(data[h] >= pivot && l < h) h--;
data[l] = data[h];
while(data[l]<pivot && l < h) l++;
data[h] = data[l];
}
data[l] = pivot;
qsort(data,left,l-1);
qsort(data,l+1,right);
}
}

bool Sorted = false;

template<typename T=int>
void sortswap(T* data,int index,int right)
{

if(index == right)
return;
if(data[index]>data[index+1])
{
swap(data[index],data[index+1]);
Sorted = false;
}
}
template<typename T=int>
void oddEvenSort(T* data,int left = 0,int right = LEN-1)
{

int latch = (right-left)/2 + (right-left)%2;
thread threads[latch];
int start = left;

while(!Sorted)
{

Sorted = true;

for(int i = start,j = 0;j<latch;i+=2,j++)
threads[j] = thread(sortswap<T>,data,i,right);

for(int i = 0;i<latch;i++)
threads[i].join();

if(start == left)
start = left +1;
else
start = left;
}
}

template<typename T> void radixSort(T* data,int left,int right){} template<> void radixSort<u32>(u32* data,int left, int right) { const int len = right - left + 1; u32* tmp = new u32[len]; for(u32 bit = 0;bit < 32;bit++) { u32 cnt0 = 0; u32 cnt1 = 0; for(u32 i = 0;i < len;i++) { const u32 d = data[i]; const u32 bit_mask = (1<<bit); if(d & bit_mask) tmp[cnt1++] = d; else tmp[len - cnt0++ - 1] = d; } for(u32 i = 0;i < cnt0;i++) data[i] = tmp[len - i -1]; for(u32 i = 0;cnt0 < len;i++) data[cnt0++] = tmp[i]; } delete[] tmp; }

template<typename T>
void (*f[])(T*,int,int) =
{
qsort,
//bubbleSort,
//oddEvenSort,
radixSort
};
int main()
{

TYPE* data = new TYPE[LEN];
for(int i = 0;i<2;i++)
{
init<TYPE>(data,LEN);
auto t1 = clock();
f<TYPE>[i](data,0,LEN-1);
cout<<(double)(clock()-t1)/CLOCKS_PER_SEC<<endl;
//disp(data,100);
}
delete[] data;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ 算法