k路合并_败者树算法

来源:互联网 发布:中国向何处去 知乎 编辑:程序博客网 时间:2024/06/16 00:39
假定有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()方法当该归并段取完后提供全局最大,以保证所有元素被挤出败者树,最后树里剩下的应该全是全局最大。**
原创粉丝点击