多路归并排序

来源:互联网 发布:傲天海网络机顶盒升级 编辑:程序博客网 时间:2024/05/31 13:14

我们有如下一个问题:对于若干个长度相同的序列,将其合并成一个有序的序列。

暴力的方法显然是不可取的,这里可以利用优先队列来处理这个问题。首先从简单的开始,对于2路归并排序,设两个序列为{A},{B},将{A},{B}排序,有

A1<=A2<=A3<=...<=An

B1<=B2<=B3<=...<=Bn

建立一个优先队列,队列中首先存入元素(A1,0),(B1,1),其中标志0,1分别表示元素中的值属于第一个序列还是第二个序列,那么第一次从队列中取出的即是此刻的最小值,这时候我们再将取出元素所在的序列的下一个元素放入队列,例如首先取出的是(A1,0),那么放入队列中的即是(A2,0),这为什么是正确的呢?因为对于A1,B1来说,若取出的是A1,那么A1<B1,于是又A1<B1<B2,那么下一个比较的必然是A2和B1,绝不可能取出时B2,于是我们加入(A2,0)。

说到这里k路归并排序的算法也就呼之欲出了,很显然每次放入的元素加上一个序列的列号,然后再优先队列里面操作即可。算法的复杂度:假设一共有n个元素,有k个序列,每次存取复杂度为logk(用C++的STL即可),总的复杂度为O(nlogk)。

c++实现:

[cpp] view plaincopy
  1. struct Item{  
  2.     int v,num;  
  3.     Item(int v,int num):v(v),num(num){}  
  4.     bool operator < (const Item& a)const{  
  5.         return v>a.v;  
  6.     }  
  7. };  
  8.   
  9. void merge(int* A,int* B,int* C,int n){  
  10.     priority_queue<Item> q;  
  11.     q.push(Item(A[0],0));  
  12.     q.push(Item(B[0],1));  
  13.     int cnt1=0,cnt2=0;//记录序列1和2的指针位置  
  14.     for(int i=0;i<n;i++){  
  15.         Item cur=q.front();q.pop();  
  16.         C[i]=cur.v;  
  17.         if(cur.num==0){  
  18.             if(cnt1<n)q.push(Item(A[++cnt1],0));  
  19.             else q.push(Item(B[++cnt2],1));  
  20.         }else{  
  21.             if(cnt2<n)q.push(Item(B[++cnt2],1));  
  22.             else q.push(Item(A[++cnt1],0));  
  23.         }  
  24.     }  
  25. }  

问题举例:

有这样k个序列,A1,A2,...,An,

     B1,B2,...,Bn,

....

每一个序列中取一个元素,求这k个元素的和,共有k^k个和,求最小的k的和,

首先还是看两个序列:A1+B1<=A1+B2<=...<=A1+Bn

A2+B1<=A2+B2<=...<=A2+Bn

...

An+B1<=An+B2<=...<=An+Bn

那么对上述序列进行归并排序即可求得答案,注意的是我们用二元组(s,b)来表示一个元素,s是和,b是B的下标,那么下一次要存入的元素即是(s-B[b]+B[b+1],b+1)

代码如下:

[cpp] view plaincopy
  1. struct Item{  
  2.     int s,b;  
  3.     Item(int s,int b):s(s),b(b){}  
  4.     bool operator < (const Item& a) const{  
  5.         return s>a.s;  
  6.     }  
  7. };  
  8.   
  9. void merge(int* A,int* B,int* C,int n){  
  10.     priority_queue<Item> q;  
  11.     for(int i=0;i<n;i++)  
  12.         q.push(Item(A[i]+B[0],0));  
  13.     for(int i=0;i<n;i++){  
  14.         Item head=q.top();  
  15.         q.pop();  
  16.         C[i]=head.s;  
  17.         int b=head.b;  
  18.         if(b+1<n)q.push(Item(head.s-B[b]+B[b+1],b+1));  
  19.     }  
  20. }  
原创粉丝点击