假定有k个有序数组,每个数组中含有n个元素,您的任务是将它们合并为单独的一个有序数组,该数组共有kn个元素。设计和实现 一个有效的分治算法解决k-路合并操作问题,并分析时间复杂度。
介于本人水平有限,在参考了许多大神的博客后贴上自己的代码;
public class MultipleMerge {
public static void main(String[] args) {
// TODO Auto-generated method stub
arr=new int[K][];
arr[0]=new int[]{-1,0,2,2,3,4,5,88};
arr[1]=new int[]{-4,1,2,4,6,8,10,11,23,45};
arr[2]=new int[]{-3,1,4,5,61,72,82,99};
arr[3]=new int[]{5,6,7,8,9,10};
arr[4]=new int[]{-5,3,66,88};
record=new int[arr.length];
for(int i=0;i<arr.length;i++){
totalCount+=arr[i].length;
record[i]=0;
}
System.out.println(Arrays.toString(K_merge()));
}
static int[][] arr=null;//多段合并的数据,每行必须有序
static final int K=5;//数组行数
static int[] record=null;//记录每个归并段出去了多少个元素
static int totalCount=0;//记录所有元素的个数
static final int MINKEY=-100;
static final int MAXKEY=100;
static int[] ls=new int[K];//败者树
static int[] b=new int[K+1];
/*
* 败者树是完全二叉树,因此数据结构可以采用一维数组。
* 其元素个数为k个叶子结点、k-1个比较结点、1个冠军结点共2k个。
* ls[0]为冠军结点,ls[1]--ls[k-1]为比较结点,ls[k]--ls[2k-1]为叶子结点
*/
//ls数组是建立的败者树,ls[i]的值是b数组的下标
public static int[] K_merge(){
/*
* ls[0]~ls[k-1]是败者树的内部比较节点
* b[0]~b[k-1]分别存储k个数组的当前记录
*/
createLoserTree();
int[] result=new int[totalCount];
int k=0;
int q=0;
while(k!=totalCount){
q=ls[0];//最小元素在b数组中的下标号
result[k++]=b[q];//将最小的元素存入结果数组
b[q]=Get_next(q);//补位
adjust(q);//调整
}
return result;
}
public static void createLoserTree() {
for (int i = 0; i < K; i++) {
b[i]=Get_next(i);//从第i个数组中读取下一个对象
}
b[K]=MINKEY;//全局最小量
for(int i=0;i<K;i++){//设置ls中的败者初值
ls[i]=K;//这样第k+1项就是最小值,前k项充满败者树
}
for(int i=K-1;i>=0;i--){
//从b[k-1]到b[0]调整败者
adjust(i);
}
//败者树创建完毕,最小关键字序号存入ls[0]
}
private static void adjust(int adjustIndex) {
//根据上一步确定的最小元素的下标调整败者树
int temp=0;
int parent=(adjustIndex+K)/2;//父节点
while(parent>0){//没有达到树根则继续
if(b[adjustIndex]>b[ls[parent]]){
//如果待调整的元素大于父节点则其变成败者
temp=ls[parent];
ls[parent]=adjustIndex;
adjustIndex=temp;
}
parent=parent/2;
}
ls[0]=adjustIndex;//最后的败者放在根节点,胜者放在0标位
}
private static int Get_next(int arrayIndex) {
//导入最小元素对应数组的下一个元素
if(record[arrayIndex]==arr[arrayIndex].length){
return MAXKEY;//当该归并段取完了返回一个全局最大
}
return arr[arrayIndex][record[arrayIndex]++];
}
}
**主要的思路:
b[]数组里存着每个数组的当前元素;
ls[]败者树数组里是存的是对b数组下标的索引;
createLoserTree():先将败者树充满K,即默认第K+1项为全局最小项,然后用前K项逐步调整,然后前K项充满败者树。
在K_merge()中通过Get_next()一步步adjust(),直到结果数组填满。
注意,Get_next()方法当该归并段取完后提供全局最大,以保证所有元素被挤出败者树,最后树里剩下的应该全是全局最大。**