排序算法(七)---- 非比较排序

一.计数排序
顾名思义,通过记录原序列中的每个数据出现的次数,然后将其保存在辅助空间的对应位置(位置=当前数据-最小数据),通过分析辅助空间和原序列,可以将原序列变成有序序列
算法如下:
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),算法稳定
通过上面的分析,很容易发现计数排序适用于数据密集,有大量数据重复的序列
二.基数排序
对于基数排序,也叫多关键码排序,在对指定数据进行排序之前,将这些数据的多个关键字从高到低进行划分,由此排序方式也就分为最高位优先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),且算法稳定
通过上述分析,可以发现基数排序适用于具有多个关键码的数据排序,而且这些数据不一定是数字
附上一张图(所有排序算法的时间复杂度,空间复杂度以及稳定性)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值