您的位置:首页 > 其它

排序算法之计数&基数排序

2016-12-03 10:52 225 查看
计数排序>

   给定一组待排序的数据,找到这组数据中的最大值,然后开辟一个最大值加1的数组,用memset初始化为全0,然后再次遍历原数组,使得这个新开辟的数组中存储的是该数字出现的次数,此时只需要将新数组的内容写入原数组即可.

     


      我们发现计数排序其实利用的是哈希的思想来统计次数,是一种非比较的排序,它的时间复杂度为O(N+范围),因为计数排序是一种以空间换取时间的排序算法.

 计数排序的优化>

      如果给定这样一组数据"1001,1002,1003",那仫按照之前的思路我们就需要开辟1004块空间,很明显存在极大的空间浪费.要优化它只能从减小开辟空间的个数入手了.

      其实我们可以找出一组数据中的最大值和最小值,此时开辟的辅助数组只需要开辟max-min+1块即可,在统计次数要重新映射进辅助数组.

     

void CountSort(int *a,int size)
{
assert(a);
int max=a[0];
int min=a[0];
//找到最大最小值
for (int i=0;i<size;++i)
{
if(a[i] > max)
max=a[i];
if(a[i] < min)
min=a[i];
}
int range=max-min+1;
int *tmp=new int[range];
memset(tmp,0,sizeof(int)*range);
//统计数字出现的次数
for (int i=0;i<size;++i)
{
tmp[a[i]-min]++;
}
//还原初始数组
int index=0;
for (int i=0;i<range;++i)
{
while (tmp[i]--)
{
a[index++]=i+min;
}
}
delete[] tmp;
}


 

 

基数排序>

     基数排序是另一种非比较的排序,类似哈希桶.它的主要思想是:从低位开始将一组序列按照这一位值的大小放至相应的编号0~9中。等到低位排完之后再按照类似的想法继续排次低位,直至排到最高位为止,此时这个序列就是有序的序列.

    

int GetMaxDigit(int *a,int size)
{
//标识数量级
int base=10;
//统计最大数据的位数
int digit=1;
for (int i=0;i<size;++i)
{
while (a[i] >= base)
{
++digit;
base *= 10;
}
}
return digit;
}
void LSDSort(int *a,int size)
{
assert(a);
int base=1;
int digit=GetMaxDigit(a,size);
int *count=new int[10];
int *start=new int[10];
int *tmp=new int[size];
while(digit--)
{
//统计数字出现的次数
memset(count,0,sizeof(int)*size);
for (int i=0;i<size;++i)
{
count[(a[i]/base)%10]++;
}
//求每组数据的起始位置
start[0]=0;
for (int i=1;i<10;++i)
{
start[i]=start[i-1]+count[i-1];
}
//将数据写入tmp中
for (int i=0;i<size;++i)
{
int num=(a[i]/base)%10;
tmp[start[num]]=a[i];
start[num]++;
}
//将tmp中的内容写入a中
for (int i=0;i<size;++i)
{
a[i]=tmp[i];
}
base *= 10;
}
delete[] tmp;
}


 

  

    在上述找最大位的方法先设置数量级base=10,digit统计位数=1,遍历数组,如果存在大于等于数量级的数就更新数量级统计位数加1.当然这个方法不太好理解,另一种求位数的方法是:先遍历一遍数组找到数组中的最大值,求出最大值的位数.

   基数排序的时间复杂度为O(N*digit),digit是这组待排序数据中的最大位,它的空间复杂度为O(N),基数排序是一种稳定的排序算法.

   在这里就分享结束啦~~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息