基数排序 Warning  本页面要介绍的不是 计数排序  。
本页面将简要介绍基数排序。
简介 基数排序(英语:Radix sort)是一种非比较型的排序算法,最早用于解决卡片排序的问题。
它的工作原理是将待排序的元素拆分为   个关键字(比较两个元素时,先比较第一关键字,如果相同再比较第二关键字……),然后先对第   关键字进行稳定排序,再对第   关键字进行稳定排序,再对第   关键字进行稳定排序……最后对第一关键字进行稳定排序,这样就完成了对整个待排序序列的稳定排序。
基数排序需要借助一种 稳定算法  完成内层对关键字的排序。
通常而言,基数排序比基于比较的排序算法(比如快速排序)要快。但由于需要额外的内存空间,因此当内存空间稀缺时,原地置换算法(比如快速排序)或许是个更好的选择。
基数排序的正确性可以参考 《算法导论(第三版)》第 8.3-3 题的解法  或自行理解。
性质 稳定性 基数排序是一种稳定的排序算法。
时间复杂度 一般来说,如果每个关键字的值域都不大,就可以使用 计数排序  作为内层排序,此时的复杂度为  ,其中   为第   关键字的值域大小。如果关键字值域很大,就可以直接使用基于比较的   排序而无需使用基数排序了。
空间复杂度 基数排序的空间复杂度为  。
算法实现 伪代码 C++  1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 const   int   N   =   100010 ;  
const   int   W   =   100010 ;  
const   int   K   =   100 ;  
int   n ,   w [ K ],   k ,   cnt [ W ];  
struct   Element   {  
   int   key [ K ];  
   bool   operator < ( const   Element &   y )   const   {  
     // 两个元素的比较流程 
     for   ( int   i   =   1 ;   i   <=   k ;   ++ i )   {  
       if   ( key [ i ]   ==   y . key [ i ])   continue ;  
       return   key [ i ]   <   y . key [ i ];  
     }  
     return   false ;  
   }  
}   a [ N ],   b [ N ];  
void   counting_sort ( int   p )   {  
   memset ( cnt ,   0 ,   sizeof ( cnt ));  
   for   ( int   i   =   1 ;   i   <=   n ;   ++ i )   ++ cnt [ a [ i ]. key [ p ]];  
   for   ( int   i   =   1 ;   i   <=   w [ p ];   ++ i )   cnt [ i ]   +=   cnt [ i   -   1 ];  
   // 为保证排序的稳定性,此处循环i应从n到1 
   // 即当两元素关键字的值相同时,原先排在后面的元素在排序后仍应排在后面 
   for   ( int   i   =   n ;   i   >=   1 ;   -- i )   b [ cnt [ a [ i ]. key [ p ]] -- ]   =   a [ i ];  
   memcpy ( a ,   b ,   sizeof ( a ));  
}  
void   radix_sort ()   {  
   for   ( int   i   =   k ;   i   >=   1 ;   -- i )   {  
     // 借助计数排序完成对关键字的排序 
     counting_sort ( i );  
   }  
}  
实际上并非必须从后往前枚举才是稳定排序,只需对 cnt 数组进行等价于 std::exclusive_scan 的操作即可。
例题 洛谷 P1177 【模板】快速排序   给出   个正整数,从小到大输出。
  1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 #include   <algorithm>  
#include   <iostream>  
#include   <utility>  
void   radix_sort ( int   n ,   int   a [])   {  
   int   * b   =   new   int [ n ];    // 临时空间 
   int   * cnt   =   new   int [ 1   <<   8 ];  
   int   mask   =   ( 1   <<   8 )   -   1 ;  
   int   * x   =   a ,   * y   =   b ;  
   for   ( int   i   =   0 ;   i   <   32 ;   i   +=   8 )   {  
     for   ( int   j   =   0 ;   j   !=   ( 1   <<   8 );   ++ j )   cnt [ j ]   =   0 ;  
     for   ( int   j   =   0 ;   j   !=   n ;   ++ j )   ++ cnt [ x [ j ]   >>   i   &   mask ];  
     for   ( int   sum   =   0 ,   j   =   0 ;   j   !=   ( 1   <<   8 );   ++ j )   {  
       // 等价于 std::exclusive_scan(cnt, cnt + (1 << 8), cnt, 0); 
       sum   +=   cnt [ j ],   cnt [ j ]   =   sum   -   cnt [ j ];  
     }  
     for   ( int   j   =   0 ;   j   !=   n ;   ++ j )   y [ cnt [ x [ j ]   >>   i   &   mask ] ++ ]   =   x [ j ];  
     std :: swap ( x ,   y );  
   }  
   delete []   cnt ;  
   delete []   b ;  
}  
int   main ()   {  
   std :: ios :: sync_with_stdio ( false );  
   std :: cin . tie ( 0 );  
   int   n ;  
   std :: cin   >>   n ;  
   int   * a   =   new   int [ n ];  
   for   ( int   i   =   0 ;   i   <   n ;   ++ i )   std :: cin   >>   a [ i ];  
   radix_sort ( n ,   a );  
   for   ( int   i   =   0 ;   i   <   n ;   ++ i )   std :: cout   <<   a [ i ]   <<   ' ' ;  
   delete []   a ;  
   return   0 ;  
}  
参考资料与注释 build 本页面最近更新:2022/2/13 10:36:07 ,更新历史 edit 发现错误?想一起完善? 在 GitHub 上编辑此页! people 本页面贡献者:NachtgeistW , Alisahhh , countercurrent-time , Early0v0 , Enter-tainer , H-J-Granger , hly1204 , Ir1d , Konano , ksyx , ouuan , partychicken , sbofgayschool , SukkaW copyright 本页面的全部内容在 CC BY-SA 4.0  和 SATA   协议之条款下提供,附加条款亦可能应用