基数排序与桶排序

基数排序

基数排序是桶排序的扩展,是非比较排序.主要思路如下:

  • 把数字从低位到高位抽取出来,抽取出来相应的数值作为计数数组的下标,更新计数数组
  • 并把数字放入与其对应数位相同数值的桶中,直至每个数字都操作到
  • 再把桶中的数值赋值到原来的数组
  • 重复上述的操作,直至轮数等于最大值的位数

表示太麻烦了,直接给图:

注意:这里省去了每次从桶中赋值到数组的操作. 实际上每次从桶中赋值后,数组是这样的:

 那就开始写代码:

首先得确定轮数,轮数由最大值的位数决定,所以这个函数确定最大值的位数:

int getloop(int nums[],int len)
{
	int j=0;
	int nmax=nums[0];
	for (int i=0;i<len;i++)
	{
		if (nmax<nums[i]) nmax=nums[i];
	}
	while (nmax>0)
	{
		nmax=nmax/10;
		j++;
	}
	return j;	
	
}

 然后就是对序列排序


//传入的数字 以及求哪位的数值 
int getDigit(int nums,int i)
{
	return (nums/((int)pow(10,i-1)))%10;
}

void radixSort(int nums[],int left,int right)
{
	int tmp[right-left+1];	//辅助数组与原数组大小一样 
	int count[10];				//计数数组,0-9
	int loop=getloop(nums,right+1);	//一共的轮数
	
	for (int d=1;d<=loop;d++)
	{
		for (int i=0;i<10;i++) count[i]=0;	//计数数组初始化
		
		for (int i=left;i<=right;i++)
		{
			int digit=getDigit(nums[i],d);
			count[digit]++;				//把得到的d位的数值计数	
		} 
	 
	 	for (int j=1;j<10;j++)
		{
			count[j]=count[j]+count[j-1];	//求出<=j的数组之和 	
		} 
	 
	 	//这里我们把得到的数字放入辅助数组 
		for (int i=right;i>=left;i--)
		{
			int digit=getDigit(nums[i],d);	//得到nums[i]数字的第d位数值
			tmp[count[digit]-1]=nums[i]; 	
            //把nums[i]的数字放入tmp数组的第 count[digit]-1位(下标-1,从0开始) 		
			
            // 为什么放在count[digit]-1位:
			// 我个人理解是,这是从最后开始往前找的,所以不管如何放,它的相对位置一定在最后。 
		
			count[digit]--;					//拿走了一个数字,就减1 
		}
		
		//把tmp赋值给原数组
		for (int i=left,j=0;i<=right;i++,j++)
		{
			nums[i]=tmp[j];
		} 
	 	
	} 
	 
}

完整代码:

#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;


int getloop(int nums[],int len)
{
	int j=0;
	int nmax=nums[0];
	for (int i=0;i<len;i++)
	{
		if (nmax<nums[i]) nmax=nums[i];
	}
	while (nmax>0)
	{
		nmax=nmax/10;
		j++;
	}
	return j;	
	
}

//传入的数字 以及求哪位的数值 
int getDigit(int nums,int i)
{
	return (nums/((int)pow(10,i-1)))%10;
}

void print(int nums,int len)
{
	for (int i=0;i<len;i++) cout<<nums[i]<<" ";
	cout<<endl;
}

void radixSort(int nums[],int left,int right)
{
	int tmp[right-left+1];	//辅助数组与原数组大小一样 
	int count[10];				//计数数组,0-9
	int loop=getloop(nums,right+1);	//一共的轮数
	
	for (int d=1;d<=loop;d++)
	{
		for (int i=0;i<10;i++) count[i]=0;	//计数数组初始化
		
		for (int i=left;i<=right;i++)
		{
			int digit=getDigit(nums[i],d);
			count[digit]++;				//把得到的d位的数值计数	
		} 
	 
	 	for (int j=1;j<10;j++)
		{
			count[j]=count[j]+count[j-1];	//求出<=j的数组之和 	
		} 
	 
	 	//这里我们把得到的数字放入辅助数组 
		for (int i=right;i>=left;i--)
		{
			int digit=getDigit(nums[i],d);	//得到nums[i]数字的第d位数值
			tmp[count[digit]-1]=nums[i]; 	
            //把nums[i]的数字放入tmp数组的第 count[digit]-1位(下标-1,从0开始) 		
			
            // 为什么放在count[digit]-1位:
			// 我个人理解是,这是从最后开始往前找的,所以不管如何放,它的相对位置一定在最后。 
		
			count[digit]--;					//拿走了一个数字,就减1 
		}
		
		//把tmp赋值给原数组
		for (int i=left,j=0;i<=right;i++,j++)
		{
			nums[i]=tmp[j];
		} 
	 print(nums,right);	
	} 
	 
}

int main()
{
	int nums[]={10,162,3,34,55,65,15,78};
	//cout<<getDigit(nums,sizeof(nums)/sizeof(int));
	 radixSort(nums,0,sizeof(nums)/sizeof(int)-1);

}

结果与我们模拟的情况也对应上了 

n:表示待排序元素的个数。 k:表示待排序元素的最大值。d:表示待排序元素的位数。

时间复杂度:o(d(n+k)) 也可以认为是:o(n*k)

空间复杂度:开辟了两个数组 所以是o(k+n)  n 是tmp大小 k 是计数数组大小

同时也是一种稳定的算法

桶排序

这里主要介绍它的思想方法:

  • 之前的计数排序与基数排序都用到了桶排序的思想
  • 桶排序:为序列分配n个桶,每个桶限定范围,把满足范围的元素加入符合的桶中
  • 再在桶中对加入的元素排序
  • 最后把桶中的元素拿出来,即为有序序列

复杂度分析,借用马士兵老师的总结:

同时它也是一个稳定性的算法. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值