一.计数排序
顾名思义,通过记录原序列中的每个数据出现的次数,然后将其保存在辅助空间的对应位置(位置=当前数据-最小数据),通过分析辅助空间和原序列,可以将原序列变成有序序列
算法如下:
void CountSort(int arr[],int size)
{
int i=0;
int max=arr[0];
int min=arr[0];
for(i=1;i<size;i++)//获得最大最小值
{
if(arr[i]>max)
max=arr[i];
if(arr[i]<min)
min=arr[i];
}
int len=max-min+1;
int* count=new int[len];
memset(count,0,len*sizeof(arr[0]));
for(i=0;i<size;i++)
{
count[arr[i]-min]++;
}
for(i=1;i<len;i++)
{
count[i]=count[i]+count[i-1];//得到第i个数据的末尾位置+1(即第i+1个数据的初始位置)
}
int* tmp=new int[size];
for(i=size-1;i>=0;i--)//从右到左,保证算法的稳定性
{
tmp[count[arr[i]]-1]=arr[i];
count[arr[i]]--;
}
memcpy(arr,tmp,size*sizeof(arr[0]));
}
时间复杂度为O(size+len),空间复杂度为O(len),算法稳定
通过上面的分析,很容易发现计数排序适用于数据密集,有大量数据重复的序列
二.基数排序
②LSD
参考博客:
基数排序 - kaizenly - 博客园
对于基数排序,也叫多关键码排序,在对指定数据进行排序之前,将这些数据的多个关键字从高到低进行划分,由此排序方式也就分为最高位优先MSD和最低位优先LSD两种方式
MSD,LSD两种方式的基本方法:
①统计每个桶中的数据个数;
②统计每个桶的起始地址(或者末尾地址)
③将数据放至桶中;
④回收桶中的数据;
⑤根据下一个关键码进行排序,重复上述;
而对于MSD方式,则可以在将数据放至桶中之后,对这个桶中的数据重新根据下一个关键码进行划分子桶,最后进行统一回收
算法如下:
①MSD
int Pow(int x,int y)
{
int ret=1;
while(y--)
{
ret*=x;
}
return ret;
}
void BaseSort_MSD(int arr[],int size,int n)
{
int count[10];
memset(count,0,10*sizeof(count[0]));
int i=0;
for(i=0;i<size;i++)
{
count[arr[i]/Pow(10,n-1)]++;
}
for(i=1;i<10;i++)
{
count[i]=count[i]+count[i-1];
}
int* bucket=new int[size];
for(i=size-1;i>=0;i--)//从右向左,保证稳定性
{
bucket[count[arr[i]/Pow(10,n-1)]-1]=arr[i];
count[arr[i]/Pow(10,n-1)]--;
}
memcpy(arr,bucket,size*sizeof(arr[0]));
delete[] bucket;
for(i=0;i<10;i++)
{
size=count[i+1]-count[i];
if(size>1)
BaseSort_MSD(arr,size,n-1);
}
}
②LSD
int Pow(int x,int y)
{
int ret=1;
while(y--)
{
ret*=x;
}
return ret;
}
void BaseSort_LSD(int arr[],int size,int n)
{
int count[10];
int* bucket=new int[size];
int i=0;
int m=1;
while(m<=n)
{
memset(count,0,sizeof(count));
for(i=0;i<size;i++)
{
count[arr[i]%Pow(10,m)/Pow(10,m-1)]++;
}
for(i=1;i<10;i++)
{
count[i]=count[i]+count[i-1];
}
for(i=size-1;i>=0;i--)//从右向左,保证稳定性
{
bucket[count[arr[i]%Pow(10,m)/Pow(10,m-1)]-1]=arr[i];
count[arr[i]%Pow(10,m)/Pow(10,m-1)]--;
}
memcpy(arr,bucket,size*sizeof(arr[0]));
m++;
}
delete[] bucket;
}
对于基数排序,时间复杂度为O(N*基数位数),空间复杂度为O(N),且算法稳定
通过上述分析,可以发现基数排序适用于具有多个关键码的数据排序,而且这些数据不一定是数字
附上一张图(所有排序算法的时间复杂度,空间复杂度以及稳定性)