线性时间排序

    夜深人静的时候,最好写代码,趁着大家熟睡之际,复习一下这几种排序方法。原理再算法导论上都有。

计数排序

     计数排序算法的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。 当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改。 

     时间复杂度分析:o(n+k),k数组中的最大值。计数排序是稳定的。但是对数据分布不均匀数组,计数排序的空间复杂度和时间复杂度毫无优势。例如:{2,1,4,10000},用计数排序太大了。

/*copyright @lsj on juyuan*/
#include <iostream>
#include <algorithm>
#include <cassert>
using namespace std;

void Output(int arr[],int len)
{
	assert(arr && len>=0);

	for(int i=0; i<len; ++i)
		cout<<arr[i]<<" ";
	cout<<endl;
}

void CountSort(int arr[],int len)
{
	int maxElem = *max_element(arr,arr+len);
	int *countArr = new int[maxElem+1];
	memset(countArr,0,sizeof(int)*(maxElem+1));
	int *temp = new int[len];
    assert(temp && countArr);

	int i;

	for(i=0; i<len; ++i)
		countArr[arr[i]]++;
	for(i=1; i<=maxElem; ++i)
		countArr[i] += countArr[i-1];
	for(i=len-1; i>=0; --i){
		temp[countArr[arr[i]]-1] = arr[i];
		--countArr[arr[i]];
	}

	memcpy(arr,temp,len*sizeof(int));

	delete[] countArr;
	delete[] temp;
}


int main()
{
	const int size = 8;
	int arr[size] = {12,3,4,53,5,6,11,90};

	Output(arr,size);
	CountSort(arr,size);
	Output(arr,size);

	system("pause");
	return 0;
}


桶排序

     先确定你的桶有多大,然后根据数组中的最大值和最小值算出max-min算出我们需要多少桶。

             barrelNum = (max-min+1)/barrelSize + 1

然后,根据每个元素的大小,计算应该放在哪个桶里面:

             index =  (arr[i]-min)/barrelSize

最后对每个桶采用插入排序,本文简单的采用了快排(小数据时,插入排序性能更好)。最后合起来输出就ok了。

     时间复杂度分析:期望运行时间为o(n),即使输入不满足均匀分布也能满足。但是如果输入不满足均匀分布,空间复杂度太高,因为很多桶都是空着的,划不来。{2,1,4,10000},几乎桶全部是空的。

/*copyright @lsj on juyuan*/
#include <iostream>
#include <algorithm>
#include <cassert>
using namespace std;

void Output(int arr[],int len)
{
	assert(arr && len>=0);

	for(int i=0; i<len; ++i)
		cout<<arr[i]<<" ";
	cout<<endl;
}

const int barrelSize = 10;
typedef struct __bucket{
	int data[barrelSize];
	int curNum;
}Bucket;

void BucketSort(int arr[],int len)
{
	assert(arr && len>=0);

	int maxElem = *max_element(arr,arr+len);
	int minElem = *min_element(arr,arr+len);

	int bucketNum = (maxElem - minElem + 1)/barrelSize + 1;

	Bucket *pBarrel = new Bucket[bucketNum];
	memset(pBarrel,0,sizeof(Bucket)*bucketNum);
	assert(pBarrel);

	int i;
	for(i=0; i<len; ++i){
		int bucketIndex = (arr[i]-minElem)/barrelSize;
		pBarrel[bucketIndex].data[pBarrel[bucketIndex].curNum++]=arr[i];
		
	}

	int pos = 0;
	for(i=0; i<bucketNum; i++){
		if(pBarrel[i].curNum!=0)
			sort(pBarrel[i].data,pBarrel[i].data+pBarrel[i].curNum);
		for(int j=0; j<pBarrel[i].curNum; ++j)
			arr[pos++] = pBarrel[i].data[j];
	}

	delete[] pBarrel;
}


int main()
{
	const int size = 8;
	int arr[size] = {12,3,4,13,5,6,11,90};

	Output(arr,size);
	BucketSort(arr,size);
	Output(arr,size);

	system("pause");
	return 0;
}


基数排序

     原理就不啰嗦了,下面程序中我利用了队列的先进先出原则。并没有像算法导论那样用到计数排序来做。感觉程序编的不是很好。这哥们说的对,我这么写,只是说明了一下基数的原理,没有把“鸡排的优势”发挥出来:http://www.2cto.com/kf/201110/106784.html

      基数排序的时间复杂度:给定n个d位数,每一个数位可以运行k种可能的值。如果所用的计数排序为o(d+k),则基数排序的时间复杂度o(d(n+k))。

/*copyright @lsj on juyuan*/
#include <algorithm>
#include <cassert>
#include <vector>
#include <queue>
using namespace std;

void Output(int arr[],int len)
{
	assert(arr && len>=0);

	for(int i=0; i<len; ++i)
		cout<<arr[i]<<" ";
	cout<<endl;
}


void RadixSort(int arr[],int len)
{
	assert(arr && len>=0);
	
	vector<queue<int> > radixQueue(10);
	int *temp = new int[len];
	assert(temp);

	int i = 0;
	bool notFinish = true;
	int base = 1;

	while(notFinish){
		notFinish = false;
		for(i=0; i<len; i++){
			int num = (arr[i] / base) % 10;
			radixQueue[num].push(arr[i]);
			if(arr[i]/(10*base) != 0)
				notFinish = true;
		}
		int pos = 0;
		for(i=0; i<=9; ++i){
			while(!radixQueue[i].empty()){
				temp[pos++] = radixQueue[i].front();
				radixQueue[i].pop();
			}
		}
		for(i=0; i<len; i++)
			arr[i] = temp[i];
		base *= 10;
	}
	
	delete[] temp;
}


int main()
{
	const int size = 8;
	int arr[size] = {12,32,4,1213,5,6,11,90};

	Output(arr,size);
	RadixSort(arr,size);
	Output(arr,size);

	system("pause");
	return 0;
}


这个找最大的位数程序不错(这就是上面哥们写的代码,学习)

int maxbit(int L[],int n)  {  
	int d = 1,i=0; //保存最大的位数 
	int p=10; 

	for(i = 0;i < n; i++) { 
		while(L[i] >= p) { 
			p *= 10; 
			d++; 
		} 
	} 

	return d; 
} 
void radixsort(int L[],int len)  
{  
	int d = maxbit(L,len);  

	long * tmp  = (long *)malloc(len*sizeof(long)); 
	long * count  = (long *)malloc(10*sizeof(long));; //计数器,10个桶  

	long i,j,k; 
	int radix = 1; 


	for(i = 1; i <= d; i++)  
	{  //进行d次排序     
		for(j = 0; j < 10;j++) //每次分配前清空计数器 
			count[j] = 0;  
		for(j = 0;j < len; j++)  
		{ //统计每个桶中的记录数 
			k = (L[j]/radix)%10;  
			count[k]++; 
		} 

		for(j = 1;j < 10; j++) //将tmp中的位置依次分配给每个桶  
			count[j] = count[j-1] + count[j]; 

		for(j = len-1;j >= 0;j--)  
		{ //将所有桶中记录依次收集到tmp中 
			k = (L[j]/radix)%10;
			count[k]--; 
			tmp[count[k]] = L[j]; 
		} 
		for(j = 0;j < len;j++) //将临时数组的内容复制到L中 
			L[j] = tmp[j]; 

		radix = radix*10; 
	}  
	free(tmp); 
	free(count); 
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值