介绍:

  (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 }

有关更多基数排序请参考:

 

 

 

posted on 2015-06-28 22:13  星梦缘vs惜  阅读(444)  评论(0编辑  收藏  举报