(radixsort)则是属于“分配式排序”(distributionsort),基数排序法又称“桶子法”(bucketsort)或binsort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。
基本实现:
以LSD(从低位到高位)为例
一组数据:123,231,243,456,436,578,567,546,598,674,656,789,876,896,987,999
首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0:
1:231
2:
3:123 243
4:674
5:
6:456 436 546 656 876 896
7:567 987
8:578 598
9:789 999
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
231 123 243 674 456 436 546 656 876 896 567 987 578 598 789 999
重复以上步骤,最大数有多少位就重复多少次
具体代码实现:
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <string.h>
int GetMaxBit(int* array, int size) //求最大数有多少位
{
size_t count = 1;
int radix = 10;
for(size_t idx = 1;idx<size; ++idx)
{
while(array[idx]>=radix)
{
count++;
radix *= 10;
}
}
return count;
}
void RadixSortLSD(int arr[], size_t size)
{
//1.确定最大值有多少位
int bit = GetMaxBit(arr,size);
int radix = 1;
int *bucket = new int[size]; //辅助空间桶
for(size_t idx = 0;idx < bit; ++idx)
{
int count[10] = {0};
for(size_t idx = 0; idx< size; ++idx)
{
count[arr[idx]/radix%10]++;//2.统计每个radix位上出现的数字次数
}
//3.寻找每个桶的起始位置
int Addr[10] = {0};
for(size_t idx = 1;idx<10; ++idx)
{
Addr[idx] = Addr[idx-1]+count[idx-1];
}
//4.将元素放置到对应的桶中
for(size_t idx = 0; idx < size; ++idx)
{
int k = arr[idx]/radix%10;//寻找桶的位置
bucket[Addr[k]] = arr[idx];//Addr[k]是这个桶的起始位置
Addr[k]++;
}
//5.将元素放回原空间
memcpy(arr,bucket,size*sizeof(arr[0]));
radix *=10; //排序前面一位
}
delete[] bucket;
}
从最好位开始分配(MSD):
从最高位开始分配,每次分配完之后又要对每个桶中的元素分配,变为了子问题,所以采用递归
#pragma once
#include <string.h>
#include <math.h>
int GetBit(int *arr, size_t size)
{
size_t count = 1;
int radix = 10;
for(int idx = 0; idx< size; ++idx)
{
while(arr[idx]> radix)
{
count++;
radix*= 10;
}
}
return count;
}
void _RadixSort(int arr[], size_t left,size_t right, int bit,int * bucket) //因为每个桶的起始位置不同,元素数目不同,所以传入左边界和右边界,左闭右 //开
{
if(bit < 1)
return ;
int radix = (int)pow(10.0, bit -1);
int count[10] = {0};
for(size_t idx = left; idx< right; ++idx)
{
count[arr[idx]/radix%10]++;//求radix位出现的次数是为了确定每个桶的位置
}
//确定每个桶的起始位置
int Addr[10] = {0};
for(size_t idx = 1; idx < 10; ++idx)
{
Addr[idx] = Addr[idx-1] + count[idx-1];
}
//将其放入辅助空间中
for(size_t idx = left; idx < right; ++idx)
{
int k = arr[idx]/radix%10; //确定arr[idx]是属于哪个桶的
bucket[Addr[k]+left] = arr[idx];//一定要注意每个桶的起始位置;此时是以左边界left开始的,不是从0开始的
Addr[k]++;
}
memcpy(arr+left,bucket+left,(right-left)*sizeof(arr[0])); //拷贝时室对每个子桶进行拷贝,不都是对全部元素拷贝,
for(size_t idx = 0; idx < 10; ++idx)
{
if(count[idx]<=1)
continue;
else
{
int begin = left+Addr[idx]-count[idx]; //应该注意前面往桶中放元素的时候Addr[idx]已经加到了该桶的最后位置,也就是其右开区间
//所以下个子桶的起始位置时应该加上left并且减去其中的元素
int end = begin+count[idx];
_RadixSort(arr, begin, end, bit - 1, bucket);
}
}
}
void RadixSort(int arr[], size_t size)
{
int bit = GetBit(arr, size);
int *bucket= new int[size];
_RadixSort(arr,0,size,bit,bucket);
}