整数的线性排序算法-基数排序

基数排序对被排序的类型有很强的要求,如对整数的排序,就是在我们知道整数在内存中的表示方法的前提下,才得以实现。当然其对被排序类型要求严格,带来的回报就是时间复杂度达到了线性。下面是我实现的基数排序,代码包涵算法本身,测试方法,时间统计等逻辑,下面的代码可以在支持C++11的g++上直接编译通过,并运行测试。

基数排序的思路如下:
首先假设所有元素都是无符号正整数
确定基数大小,例如255,也就是每一轮比较8bit(0-255)
然后计算出需要做多少轮基数排序,每一轮基数排序做如下动作
1、统计基数范围内的每个数的个数
2、由1的统计信息,计算出每个数的起始位置
3、根据2的计算结果,将被排序元素拷贝到临时数组的相应位置。

如果是有符号数,则将整个排序集合划分为负数部分和非负数部分。
负数部分进行取反(满足正整数假设)、基数排序、反转、取反。

#include <iostream>
#include <algorithm>
#include <utility>
#include <cstdlib>
#include <ctime>
#include <random>
#include <limits>
#include <functional>
#include <type_traits>
#include <vector>
#include <chrono>
#include <cassert>

template<typename T,const unsigned int W = 8>
class radix_sort
{
	public:
		void operator()(T *a,const unsigned int sz) { return rsort(a,sz); }
	private:
		class radix_sort_impl
		{
			public:
				void operator()(T *a,const unsigned int sz);
			private:
				static constexpr unsigned int passes = sizeof(T) * 8u / W;
				static constexpr unsigned int buckets_size = (1u << W) + 1;
				static constexpr unsigned int mask = (1u << W) - 1;
				void sort(T *a,const unsigned int sz);
		};
		//if T is not integral type, produce compile error
		typedef typename std::enable_if<std::is_integral<T>::value,radix_sort_impl>::type radix_sort_impl_t;
		radix_sort_impl_t rsort;
};

template<typename T,const unsigned int W>
void radix_sort<T,W>::radix_sort_impl::sort(T *a,const unsigned int sz)
{
	std::vector<T> buckets(buckets_size);
	T *oa = a;
	T *t = new T[sz];
	for(int i = 0; i < passes; ++i)
	{
		for(auto &e : buckets)
			e = 0;
		//statistic count of every bucket
		for(int j = 0;j < sz; ++j)
			++buckets[((a[j] >> (i * W)) & mask) + 1];
		//calculate every bucket start index
		for(int j = 1; j < buckets_size; ++j)
			buckets[j] += buckets[j - 1];
		//copy to proper bucket
		for(int j = 0;j < sz; ++j)
			t[buckets[(a[j] >> (i * W)) & mask]++] = a[j];
		std::swap(a,t);
	}
	if(oa != a)
	{
		std::swap(a,t);
		for(int j = 0; j < sz; ++j)
			a[j] = t[j];
	}
	delete [] t;
	return;
}

template<typename T,const unsigned int W>
void radix_sort<T,W>::radix_sort_impl::operator()(T *a,const unsigned int sz)
{
	//if T is signed, divide into negative part and positive part
	if(std::is_signed<T>::value)
	{
		int i = 0;
		int j = sz - 1;
		while(true)
		{
			while(i < j && a[i] < 0) ++i;
			while(i < j && a[j] >= 0) --j;
			if(i < j)
				std::swap(a[i],a[j]);
			else
				break;
		}
		//sort negative part
		int negetive_size = a[i] < 0 ? i + 1 : i;
		//remove minus
		for(int k = 0; k < negetive_size; ++k)
			a[k] = -a[k];
		//sort
		this->sort(a,negetive_size);
		//reverse
		std::reverse(a,a + negetive_size);
		//add minus
		for(int k = 0; k < negetive_size; ++k)
			a[k] = -a[k];
		//sort positive part
		this->sort(a + negetive_size,sz - negetive_size);
	}
	else
	{
		this->sort(a,sz);
	}
	return;
}

//print number
int dump(int *a,int n)
{
	for(int i = 0; i < n; ++i)
	{
		std::cout << a[i] << " ";
	}
	std::cout << std::endl;
	return 0;
}
//generate random number
int gen(int *a,int n)
{
	//srand(time(NULL));
	std::default_random_engine dre(time(NULL));
	std::uniform_int_distribution<int> uid(std::numeric_limits<int>::min(),std::numeric_limits<int>::max());
	while(--n >= 0)
	{
		//a[n] = rand();
		a[n] = uid(dre);
	}
	return 0;
}
//check sort result
bool chk(int *a,int n)
{
	for(int i = 0;i < n - 1; ++i)
		if(a[i] > a[i + 1])
			return false;
	return true;
}

int main(int argc,char *argv[])
{
	if(argc != 2 && argc != 3)
	{
		return 0;
	}
	int loop = atoi(argv[1]);
	int n = 10;
	if(argc == 3)
		n = atoi(argv[2]);

	int *a = new int [n];

	radix_sort<int> rs;

	while(--loop >= 0)
	{	
		gen(a,n);
		//dump(a,n);	
		auto start = std::chrono::steady_clock::now(); 
		rs(a,n);
		auto end = std::chrono::steady_clock::now();
		assert(true == chk(a,n));
		//dump(a,n);	
		std::cout << "----------"<< std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count()<< "--------------" << std::endl;
	}
	delete [] a;
	return 0;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值