• 基数排序


    介绍:

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

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

     

    这世界上有一种鸟是没有脚的,它只能够一直的飞呀飞呀,飞累了就在风里面睡觉,这种鸟一辈子只能下地一次,那一次就是它死亡的时候。
  • 相关阅读:
    UIKit框架-高级控件Swift版本: 5.UITextView方法/属性详解
    UIKit框架-高级控件Swift版本: 3.UITableViewCell方法/属性详解
    UIKit框架-高级控件Swift版本: 2.UITableView方法/属性详解
    UIKit框架-高级控件Swift版本: 4.UICollectionView方法/属性详解
    UIKit框架-高级控件Swift版本: 1.UIScrollView方法/属性详解
    UIKit框架-基础控件Swift版本: 6.UITextField方法/属性详解
    UIKit框架-基础控件Swift版本: 5.UIImage方法/属性详解
    UIKit框架-基础控件Swift版本: 4.UIImageView方法/属性详解
    UIKit框架-基础控件Swift版本: 3.UILabel方法/属性详解
    UIKit框架-基础控件Swift版本: 2.UIButton方法/属性详解
  • 原文地址:https://www.cnblogs.com/xuyinghui/p/4606213.html
Copyright © 2020-2023  润新知