基数排序:
在待排序序列中,每个数据在各个数位上可能的取值总数称为基数。如:在十进制中,数据某一位的取值为0~9,那么基数就是10.
在八进制排序中,基数就是8.
基数排序方法有两种:一种是最高位优先(MSD),另一种是最低位优先(LSD)。
以MSD为例:
基数排序需要以下步骤:
生成count数组、将待排序元素放入对应的桶中、将排好序的桶中的元素再复制到原数组中的对应位置、递归(d由最高位转换到次高位)
(1)count[k]数组:
第i位取值为k的元素有count[k]个。
当基数为10时,k取0~9.
待排序元素:[left,right]
生成count数组,要取数据任一位的值,为此,设计一个位取数器:位取数器:
input:数据 位数
output:该位的取值
int getdigit(int num,int dt) //位取数器,num,适用范围:0~999
{
int g;
if(dt==3)
{
if(num>=0&&num<=9)
return 0;
else if(num>=10&&num<=99)
return 0;
else
return num/100;
}
if(dt==2)
{
if(num>=0&&num<=9)
return 0;
else if(num>=10&&num<=99)
return num/10;
else
{
g=num/100;
return (num-g*100)/10;
}
}
if(dt==1)
{
if(num>=0&&num<=9)
return num;
else if(num>=10&&num<=99)
{
g=num/10;
return num-g*10;
}
else
{
g=num/10;
return num-g*10;
}
}
return 0;
}
(2)用辅助数组auxArray[len]来模拟桶,每个桶的大小由count[k]来确定。
要确定每个桶在auxArray[len]中的位置:
假设有count[k]数组:
从count[k]中可以看出共有12个待排序元素,分布在0~9共10个桶中。
每个桶的位置在auxArray[12]中如下:
(4、8号桶不存在,即没有这样的待排序元素)
即:第k号桶的首个位置是:auxArray[count[0]+count[1]+…+count[k-1]]
第k号桶的下一个位置是:
auxArray[count[0]+count[1]+…+count[k-1]+1+…]现在开始将待排序的元素放到对应的桶中:
桶分两种情况:
1、 能装1个元素
2、 能装多个元素
为此,要对每一个桶设置一个计数器。在桶中每放入一个元素,这个桶 的计数器就加 1 。在桶中放入元素前,先检测计数器,用计数器来确定要放入的位置。计数器设置:
cnt[10]
初始化:int cnt[10]=0;
for(i=left;i<=right;i++)//扫描待排序元素
{ firstPos=0;//桶的首位置归零
bucket=a[i]/x; //确定哪个桶
for(j=0;j<=bucket-1;j++) //确定桶的首位置
{
firstPos=firstPos+count[j];
}
auxArray[firstPos+cnt[bucket]]=a[i];
cnt[bucket]++; //记录这个桶的下一个位置
}
(3)将排好序的桶中的元素再复制到原数组中的对应位置:
要考虑auxArray[]与a[]的对应关系:
若原数组为:a[left,right]
再假设:count[2]=1 count[3]=2 count[4]=1
那么:auxArray[]:
可以看出auxArray的大小与count[k]有关。
即auxArray[count[0]+count[1]+…+count[9]]
而且:auxArray[0]对应a[left],auxArray[1]对应a[left+1]…for(i=0;i<count[0]+…+count[9];i++)
a[left+i]=auxArray[i];
(4)递归:
由最高位转换到次高位;
递归结束的条件:if(d>0)
要确定递归的桶(即存在多个元素的桶)和这些桶的边界。
a[left,right]对应了0~9号桶。例如:
count[]:
a[](原数组):
需要递归的桶为:1、2、5、7
它们的起始下标(st)表示:
1:left+(count[0])
2:left+(count[0]+count[1])
5:left+(count[0]+count[1]+…+count[4])
7:left+(count[0]+…+count[6])
它们的终止下标表示:
1:st+count[1]-1
2:st+count[2]-1
5:st+count[5]-1
7:st+count[7]-1
for(i=0;i<10;i++)
{ s=0;st=0;ed=0;//归零
if(count[i]>1)//需要递归的桶
{
for(j=0;j<i;j++)
{
s=s+count[j];
}
st=left+s; //第i个桶的起始下标
ed=st+count[i]-1; //第i个桶的终止下标
}
radixsort(a,st,ed,d-1);
}
总结:一定要注意变量的适用范围(是否需要在下一次循环开始前置零) 声明的变量和数组要初始化
附程序:
// node.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#define len 14
void radixsort(int t[],int left,int right,int d);
int getdigit(int num,int dt);
int getdigit(int num,int dt) //位取数器
{
int g;
if(dt==3)
{
if(num>=0&&num<=9)
return 0;
else if(num>=10&&num<=99)
return 0;
else
return num/100;
}
if(dt==2)
{
if(num>=0&&num<=9)
return 0;
else if(num>=10&&num<=99)
return num/10;
else
{
g=num/100;
return (num-g*100)/10;
}
}
if(dt==1)
{
if(num>=0&&num<=9)
return num;
else if(num>=10&&num<=99)
{
g=num/10;
return num-g*10;
}
else
{
g=num/10;
return num-g*10;
}
}
return 0;
}
void radixsort(int t[],int left,int right,int d)
{
if(d>0) //递归结束的条件
{
//产生count数组
int m,n,sum,w;
int count[10]={0};
for(m=left;m<=right;m++)
{
w=getdigit(t[m],d);
count[w]++;
}
sum=0;
for(n=0;n<10;n++)
sum=sum+count[n];
//将待排序元素放入对应的桶中
int cnt[10]={0};
int auxArray[len]={0};
int bucket,firstPos,i,j;
for(i=left;i<=right;i++)
{
firstPos=0;
bucket=getdigit(t[i],d);
for(j=0;j<=bucket-1;j++)
{
firstPos=firstPos+count[j];
}
auxArray[firstPos+cnt[bucket]]=t[i];
cnt[bucket]++;
}
//将桶中的元素返回给原数组
int k;
for(k=0;k<sum;k++)
t[left+k]=auxArray[k];
/*
int tt;
for(tt=0;tt<len;tt++)
{
printf("%d",t[tt]);
printf("\t");
}
printf("\n");
*/
//递归
int a,b,s,st,ed;
for(a=0;a<10;a++)
{
s=0;st=0;ed=0;
if(count[a]>1)
{
for(b=0;b<a;b++)
s=s+count[b];
st=left+s;
ed=st+count[a]-1;
}
radixsort(t,st,ed,d-1);
}
}//if
}
void main(int argc, char* argv[])
{
int b[len]={361,9,667,26,587,3,666,103,500,79,325,46,518,45}; //increase
int r;
int ttt;
for(ttt=0;ttt<len;ttt++)
{
printf("%d",b[ttt]);
printf("\t");
}
printf("\n");
radixsort(b,0,len-1,3);
printf("\n");
for(r=0;r<len;r++)
{printf("%d",b[r]);printf("\t");}
printf("\n");
}