posts - 274,  comments - 1258,  trackbacks - 0

  今天,AC在程痴群问到一个问题:如何用O(N+K)时间,O(K)辅助空间完成对N个关键字范围为[0,K)的项的基数排序?想了一下,主要难点在O(K)空间上,也就是说,你不能另开一个大小为N的数组(否则就是无敌BC题了)。想了一下,得算法如下。
  容易想到用基数排序,但由于题目限制不能用链表或数组将其全部收集起来,便想到用数组本身做收集器,这样问题就变成如何处理将被收集的项与未被排序的项的空间冲突问题了。方法也很简单,将这两项交换,则原来将被收集的项被移到该它的归宿地,而那时的未排序项则成为下一个将被收集的项。
  具体代码如下,我用了一个c[]数组统计各关键字拥有的项的数目,然后自然可以O(K)地求出所有队列的首地址和尾地址(初始时两者相等,因为所有收集队列皆空)
  然后用i指针去扫描数组,若发现一个未被排序的项——其特征是所处下标比其收集队列的首地址还小,则将其与收集队列的尾地址上的项交换,同时将收集队列的尾指针加1。这样当i扫描到数组尾时,排序也就完成了。
  初看代码时看到for里边有个while,很容易误以为是O(N^2)的算法,但实际上它是O(N)的,证明方法很简单:对于数组中的任意一个项,它都不会被移动超过2次,不会比j指针访问超过1次,不会比i指针访问超过2次。 

/*     
    解决:用O(N+K)时间,O(K)辅助空间完成对N个关键字范围为[0,K)的项的基数排序
    最后更新:07-01-22
    提问者:AC
*/

#include
< cstdio >
#include
< cstring >

typedef 
int  T;  // 定义排序类型,以int为例
int  key(T item) {     // 对T类型定义关键字
         return  item;
}


T a[]
= { 1 , 0 , 2 , 0 , 2 , 2 , 1 , 1 } // 待排序数组
const   int  N = sizeof (a) / sizeof ( * a);
const   int  K = 3 // 排序关键字范围[0,K)

int  c[K];  // 队列计数器
int  b[K];  // 排序队列头指针
int  e[K];     // 排序队列尾指针
void  sort() {
    
int  i,j;
    memset(c,
0 , sizeof (c));
    
for (i = 0 ; i < N;  ++ i) c[key(a[i])] ++ ;
    
for (b[ 0 ] = e[ 0 ] = 0 ,i = 1 ; i < K;  ++ i)    b[i] = e[i] = b[i - 1 ] + c[i - 1 ];
    
for (i = 0 ; i < N;  ++ i) {
        
while (i < b[key(a[i])]) {     // a[i]的位置不合法
            j = e[key(a[i])] ++ ;     // j指向a[i]所属队列尾
            T tmp = a[j];    a[j] = a[i]; a[i] = tmp;  // 交换a[i],a[j]
        }

    }

}

#include
< iostream >
using   namespace  std;
int  main() {
    sort();
    
for ( int  i = 0 ; i < N;  ++ i) cout << a[i] << '   ' ;
    cout
<< '   ' ;
    
return   0 ;
}


如果你有别的算法,或者发现文中的错漏,请不吝赐教!谢谢!
posted on 2007-01-22 02:33 踏雪赤兔 阅读(1235) 评论(2)  编辑 收藏 引用 所属分类: 玩转编程

FeedBack:
# re: 解题报告:O(K)空间的基数排序
2007-01-26 01:15 | AC
thank you very much~~~!
之前有事都未来认真睇,而家明左啦!
5该晒鸡仔!~  回复  更多评论
  
# re: 解题报告:O(K)空间的基数排序
2007-01-26 23:19 | 管理制度
很另类的文章,收藏了  回复  更多评论
  
只有注册用户登录后才能发表评论。

百度空间| 见闻日记| 编程感悟
我的twitter


LOGO

自我介绍:百度厂基础平台车间的一名挨踢民工。擅长C++、算法、语言设计、分布式计算,也用过Java,Python, PHP,JS/AS等语言开发。请关注我的twitter (免翻墙版) 发QQ消息


添加到收藏夹 Locations of visitors to this page

常用链接

随笔分类(300)

随笔档案(274)

文章分类(38)

相册

收藏夹(54)

与博主互动

博客手拉手

搜索

  •  

积分与排名

  • 积分 - 399490
  • 排名 - 10

最新评论

阅读排行榜

评论排行榜