基数排序

分配排序的基本思想:排序过程无须比较关键字,而是通过“分配”和“收集”过程来实现排序。它们的时间复杂度可达到线性阶:O(n)。

一、两种多关键码排序方法

  最高位优先法(MSD法)。先按k1排序,将序列分成若干子序列,每个子序列中的记录具有相同的k1值;再按k2排序,将每个子序列分成更小的子序列;然后,对后面的关键码继续同样的排序分成更小的子序列,直到按kd排序分组分成最小的子序列后,最后将各个子序列连接起来,便可得到一个有序的序列。前面介绍的扑克牌先按花色再按面值进行排序的方法就是MSD法
  最次位优先法(LSD法)。先按kd排序,将序列分成若干子序列,每个子序列中的记录具有相同的kd值;再按kd-1排序,将每个子序列分成更小的子序列;然后,对后面的关键码继续同样的排序分成更小的子序列,直到按k1排序分组分成最小的子序列后,最后将各个子序列连接起来,便可得到一个有序的序列。前面介绍的扑克牌先按面值再按花色进行排序的方法就是LSD法。

二、基于LSD方法的链式基数排序的基本思想

  “多关键字排序”的思想实现“单关键字排序”。对数字型或字符型的单关键字,可以看作由多个数位或多个字符构成的多关键字,此时可以采用“分配-收集”的方法进行排序,这一过程称作基数排序法,其中每个数字或字符可能的取值个数称为基数。比如,扑克牌的花色基数为4,面值基数为13。在整理扑克牌时,既可以先按花色整理,也可以先按面值整理。按花色整理时,先按红、黑、方、花的顺序分成4摞(分配),再按此顺序再叠放在一起(收集),然后按面值的顺序分成13摞(分配),再按此顺序叠放在一起(收集),如此进行二次分配和收集即可将扑克牌排列有序。
      基数排序_第1张图片

三、基数排序的实现

复制代码
代码
     public   class  RadixNode < T >
    {
        
private  T data;  // 数据域
         private  RadixNode < T >  next;  // 引用域
         public  RadixNode(T val, RadixNode < T >  p)
        {
            data 
=  val;
            next 
=  p;
        }
        
public  RadixNode(RadixNode < T >  p)
        {
            next 
=  p;
        }
        
public  RadixNode(T val)
        {
            data 
=  val;
            next 
=   null ;
        }
        
public  RadixNode()
        {
            data 
=   default (T);
            next 
=   null ;
        }
        
// 数据域属性
         public  T Data
        {
            
get
            {
                
return  data;
            }
            
set
            {
                data 
=  value;
            }
        }
        
// 引用域属性
         public  RadixNode < T >  Next
        {
            
get
            {
                
return  next;
            }
            
set
            {
                next 
=  value;
            }
        }
    }
复制代码

 

复制代码
代码
     // 对顺序列表sqList进行关键字为m位整型值的基数排序
     public   void  radixSort(SeqList < int >  sqList,  int  n,  int  m)
    {
        
int  i, j, k, l, power;
        RadixNode
< int >  p, q;
        RadixNode
< int > [] head  =   new  RadixNode < int > [ 10 ];
        power 
=   1 ;
        
for  (i  =   0 ; i  <  m; i ++ )
        {
            
if  (i  ==   0 )
                power 
=   1 ;
            
else
                power 
=  power  *   10 ;
            
for  (j  =   0 ; j  <   10 ; j ++ )
            {
                head[j] 
=   new  RadixNode < int > (); ;
            }
            
for  (l  =   0 ; l  <  n; l ++ )
            {
                k 
=  sqList.Data[l]  /  power  -  (sqList.Data[l]  /  (power  *   10 ))  *   10 ;
                q 
=   new  RadixNode < int > ();
                q.Data 
=  sqList.Data[l];
                q.Next 
=   null ;
                p 
=  head[k].Next;
                
if  (p  ==   null )
                    head[k].Next 
=  q;
                
else
                {
                    
while  (p.Next  !=   null ) p  =  p.Next;
                    p.Next 
=  q;
                }
            }
            
/* 按照链的顺序收回各记录 */
            l 
=   0 ;
            
for  (j  =   0 ; j  <   10 ; j ++ )
            {
                p 
=  head[j].Next;
                
while  (p  !=   null )
                {
                    sqList.Data[l] 
=  p.Data;
                    l
++ ;
                    p 
=  p.Next;
                }
            }
        }
    }
复制代码

四、时间复杂度分析

  时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集。

你可能感兴趣的:(基数排序)