k路合并_败者树算法

假定有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()方法当该归并段取完后提供全局最大,以保证所有元素被挤出败者树,最后树里剩下的应该全是全局最大。**
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值