(radix sort)则是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的比较性排序法。
解法:
基数排序的方式可以采用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。
示例:
以LSD为例,假设原来有一串数值如下所示:
73, 22, 93, 43, 55, 14, 28, 65, 39, 81
1:首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
0
1 81
2 22
3 73 93 43
4 14
5 55 65
6
7
8 28
9 39
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
81, 22, 73, 93, 43, 14, 55, 65, 28, 39
2:接着再进行一次分配,这次是根据十位数来分配:
0
1 14
2 22 28
3 39
4 43
5 55
6 65
7 73
8 81
9 93
接下来将这些桶子中的数值重新串接起来,成为以下的数列:
14, 22, 28, 39, 43, 55, 65, 73, 81, 93
这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。
LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好,MSD的方 式恰与LSD相反,是由高位数为基底开始进行分配,其他的演算方式则都相同。
效率分析
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的 时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。 空间效率:需要2*radix个指向队列的辅助空间,以及用于静态链表的n个指针。
实现方法
最高位优先(Most Significant Digit first)法,简称MSD法:先按k1排序分组,同一组中记录,关键码k1相等,再对各组按k2排序分成子组,之后,对后面的关键码继续这样的排序分 组,直到按最次位关键码kd对各子组排序后。再将各组连接起来,便得到一个有序序列。
最低位优先(Least Significant Digit first)法,简称LSD法:先从kd开始排序,再对kd-1进行排序,依次重复,直到对k1排序后便得到一个有序序列。
代码实现:
JAVA实现代码:
1 public class RadixSort
2 {
3
4 public static void sort(int[] number, int d) {//注意参数
5
6 int k=0;
7
8 int n=1;
9
10 int m=1;
11
12 int[][] temp = new int[number.length][number.length];
13
14 int[] order = new int[number.length];
15
16 while(m <= d) {
17
18 for(int i = 0; i < number.length; i++) {
19
20 int lsd = ((number[i] / n) % 10);
21
22 temp[lsd][order[lsd]] = number[i];
23
24 order[lsd]++;
25
26 }
27
28 for(int i = 0; i < d; i++)
29 {
30
31 if(order[i] != 0)
32
33 for(int j = 0; j < order[i]; j++)
34 {
35
36 number[k] = temp[i][j];
37
38 k++;
39
40 }
41
42 order[i] = 0;
43
44 }
45
46 n *= 10;
47
48 k = 0;
49
50 m++;
51
52 }
53
54 }
55
56 public static void main(String[] args)
57 {
58 //初始化数组:
59 int[] data ={73, 22, 93, 43, 55, 14, 28, 65, 39, 81, 33, 100};
60
61 RadixSort.sort(data, 10);//函数调用
62
63 for(int i = 0; i < data.length; i++)
64 {
65
66 System.out.print(data[i] + " ");
67
68 }
69 }
习题拓展:
任务:
假设有n个待排序记录,记录Ri的关键字为Keyi, Keyi由d位十进制数字组成,即Keyi=Ki1 Ki2 Ki3 … Kid ,试分别采用链式存储结构和顺序存储结构实现基数排序。
实现代码:
1 顺序存储:
2
3 //___________________________________顺序存储________________________________________________________
4 # include <iostream.h>
5 # include <stdio.h>
6 # include <conio.h>
7 # define MAX_NUM_OF_KEY 8//关键字项数的最大值
8 # define RD 10//关键字基数,此时是十进制整数的基数
9 # define MAX_SPACE 10000
10 # define ERROR -1
11
12 typedef int KeyType;//关键字类型
13 typedef int InfoType;//数据域类型
14 typedef int ArrType[RD];//指针数组类型,存放10个队列
15
16 typedef struct SLCell//记录,静态链表的节点类型
17 {
18 KeyType keys[MAX_NUM_OF_KEY];//关键字
19 InfoType otheritmes;//其他数据项
20 int next;
21 }SLCell;
22
23 typedef struct SLList //存放记录的线性表
24 {
25 SLCell r[MAX_SPACE];//静态链表可利用的空间,r[0]为头结点
26 int keynum;//记录的当前关键字个数
27 int recnum;//静态链表的当前长度
28 }SLList;
29 //keys(L.r[i].keys[],L.r[i].otheritmes) ;
30 void keys(int keys[] ,int n)//为关键字赋值,关键字是从个位到高位一次放入数组Key[]的
31 {
32 int i;
33 for(i=0;n>0;i++)
34 {
35 keys[i]=n;
36 n=n/10;
37 }
38
39 }
40 void OutExample(SLList L,int i)
41 {
42 int p;
43 cout<<endl;
44 cout<<"第"<<i+1<<"趟搜集结果是:";
45 for(p=L.r[0].next;L.r[p].next;p=L.r[p].next)
46 {
47 cout<<L.r[p].otheritmes<<"->";
48 }
49 cout<<L.r[p].otheritmes<<endl;
50
51 }
52
53 void creatExample(SLList &L)
54 {
55 int i,j;
56 //char a[MAX_NUM_OF_KEY];
57 cout<<"请输入待排序记录的个数:"<<endl;
58 cin>>L.recnum;
59 cout<<"请输入关键字个数:"<<endl;
60 cin>>L.keynum;
61 for(i=1;i<=L.recnum;i++)//给关键字初始化为0
62 {
63 for(j=0;j<L.recnum;j++)
64 L.r[i].keys[j]=0;
65 }
66 cout<<"请输入待排序记录:"<<endl;
67 for(i=1;i<=L.recnum;i++)//输入数据项
68 {
69
70 cin>>L.r[i].otheritmes;
71 keys(L.r[i].keys,L.r[i].otheritmes) ;//为关键字赋值,关键字是从个位到高位一次放入数组Key[]的
72
73 }
74 cout<<endl<<"表L为:"<<endl;
75 for(i=1;i<L.recnum;i++)//输出据项
76 cout<<L.r[i].otheritmes<<"->";
77 cout<<L.r[i].otheritmes<<endl;
78 for(i=0;i<L.recnum;i++)//给next赋值
79 L.r[i].next=i+1;
80 L.r[L.recnum].next=0;
81 }
82
83
84 void Distribute(SLList & L,int i,ArrType &f,ArrType &e)//第i趟分配,按第i个关键字搜集
85 {
86 int j,p;
87 for(j=0;j<RD;j++)//队头指针初始化
88 f[j]=0;//各子表初始化为空表
89 for(p=L.r[0].next;p;p=L.r[p].next)//p指示当前节点位置
90 {
91 j=L.r[p].keys[i];
92 if(f[j]==0)//若该子表为空
93 f[j]=p;
94 else//若该子表不空
95 L.r[e[j]].next=p;//将p指向的节点插入第个i子表中
96 e[j]=p;//表尾指针指向该节点
97 }
98 }
99
100 void Collect(SLList &L,int i,ArrType f,ArrType e)//第i趟收集
101 {
102 int j,t;
103 for(j=0;!f[j];j++);//找到第一个非空子表
104 L.r[0].next=f[j];//r[0].next指向第一个非空子表的第一个节点
105 t=e[j];//用t记录当前子表的最后一个节点
106 while(j<RD-1)
107 {
108 for(j=j+1;j<RD-1&&!f[j] ;j++);//找下一个非空子表
109 if(f[j])
110 {
111 L.r[t].next=f[j];
112 t=e[j];//用t记录当前子表的最后一个节点
113 }
114 }
115 L.r[t].next=0;//t指向最后一个非空子表的最后一个节点
116 OutExample(L,i);
117 }
118
119 void RadixSort(SLList &L)//基数排序
120 {
121 int i;
122 ArrType f,e;//队头指针,队尾
123 for(i=0;i<L.keynum;i++)//进行keynum趟分配,收集
124 {
125 Distribute(L,i,f,e);//第i趟分配
126 Collect(L,i,f,e);//第i趟分收集
127 }
128 }
129 void main()
130 {
131 SLList L;
132 cout<<"基数排序(顺序存储).cpp"<<endl<<"============="<<endl<<endl;
133 creatExample(L);
134 RadixSort(L);
135 }
136
137
链式存储:
1 链式存储:
2
3 //___________________________________链式存储________________________________________________________
4 # include <iostream.h>
5 # include <stdio.h>
6 # include <conio.h>
7 #include<malloc.h>
8 # define MAX_NUM_OF_KEY 8//关键字项数的最大值
9 # define RD 10//关键字基数,此时是十进制整数的基数
10 # define MAX_SPACE 10000
11 # define ERROR -1
12
13 typedef int KeyType;//关键字类型
14 typedef int InfoType;//数据域类型
15
16
17 typedef struct SLCell//结点
18 {
19 KeyType keys[MAX_NUM_OF_KEY];//关键字
20 InfoType otheritmes;//其他数据项
21 struct SLCell * next;
22 }SLCell,* LNode;
23 typedef LNode ArrType[RD];//指针数组类型,存放10个队列
24
25 typedef struct SLList //存放记录的线性表
26 {
27 SLCell *H;// L 为单链表的头指针
28 int keynum;//记录的当前关键字个数
29 int recnum;//静态链表的当前长度
30 }SLList;
31 //keys(L.r[i].keys[],L.r[i].otheritmes) ;
32 void keys(int keys[] ,int n)//为关键字赋值,关键字是从个位到高位一次放入数组Key[]的
33 {
34 int i;
35 for(i=0;n>0;i++)
36 {
37 keys[i]=n;
38 n=n/10;
39 }
40
41 }
42 void OutExample(SLList L,int i)
43 {
44 SLCell * p;
45 cout<<endl;
46 cout<<"第"<<i+1<<"趟搜集结果是:";
47 for(p=L.H->next;p->next;p=p->next)
48 {
49 cout<<p->otheritmes<<"->";
50 }
51 cout<<p->otheritmes<<endl;
52
53 }
54
55 void creatExample(SLList &L)//尾插法建立链表
56 {
57 int i,j,n;
58 SLCell *p,*q;//q指向表尾
59 cout<<"请输入待排序记录的个数:"<<endl;
60 cin>>L.recnum;
61 cout<<"请输入关键字个数:"<<endl;
62 cin>>L.keynum;
63 L.H=(SLCell *)malloc(sizeof(SLCell));//头结点,尾插法建立链表
64 L.H->next=NULL;
65 q=L.H;
66 cout<<"请输入待排序记录:"<<endl;
67 for(i=1;i<=L.recnum;i++)//输入数据项
68 {
69 cin>>n;
70 p=(SLCell *)malloc(sizeof(SLCell));
71 p->otheritmes=n;
72 for(j=0;j<L.recnum;j++)//给关键字初始化为0
73 p->keys[j]=0;
74 p->next=NULL;
75 q->next=p;
76 q=p;
77 }
78 p=L.H->next;
79 while(p!=NULL)
80 {
81 keys(p->keys,p->otheritmes) ;//为关键字赋值,关键字是从个位到高位一次放入数组Key[]的
82 p=p->next;
83 }
84 cout<<endl<<"表L为:"<<endl;
85 for(i=1,p=L.H->next;i<L.recnum;i++)//输出据项
86 {
87 cout<<p->otheritmes<<"->";
88 p=p->next;
89 }
90 cout<<p->otheritmes;
91 }
92
93
94 void Distribute(SLList & L,int i,ArrType &f,ArrType &e)//第i趟分配,按第i个关键字搜集
95 {
96 int j;
97 SLCell *p;
98 for(j=0;j<RD;j++)//队头指针初始化
99 f[j]=NULL;//各子表初始化为空表
100 for(p=L.H->next;p;p=p->next)//p指示当前节点位置
101 {
102 j=p->keys[i];
103 if(f[j]==NULL)//若该子表为空
104 f[j]=p;
105 else//若该子表不空
106 e[j]->next=p;//将p指向的节点插入第个i子表中
107 e[j]=p;//表尾指针指向该节点
108 }
109 }
110
111 void Collect(SLList &L,int i,ArrType f,ArrType e)//第i趟收集
112 {
113 int j;
114 SLCell *t;
115 for(j=0;!f[j];j++);//找到第一个非空子表
116 L.H->next=f[j];//r[0].next指向第一个非空子表的第一个节点
117 t=e[j];//用t记录当前子表的最后一个节点
118 while(j<RD-1)
119 {
120 for(j=j+1;j<RD-1&&!f[j] ;j++);//找下一个非空子表
121 if(f[j])
122 {
123 t->next=f[j];
124 t=e[j];//用t记录当前子表的最后一个节点
125 }
126 }
127 t->next=NULL;//t指向最后一个非空子表的最后一个节点
128 OutExample(L,i);
129 }
130
131 void RadixSort(SLList &L)//基数排序
132 {
133 int i;
134 ArrType f,e;//队头指针,队尾
135 for(i=0;i<L.keynum;i++)//进行keynum趟分配,收集
136 {
137 Distribute(L,i,f,e);//第i趟分配
138 Collect(L,i,f,e);//第i趟分收集
139 }
140 }
141 void main()
142 {
143 SLList L;
144 cout<<"基数排序(链式存储).cpp"<<endl<<"============="<<endl<<endl;
145 creatExample(L);
146 RadixSort(L);
147 }
有关更多基数排序请参考: