编程之美【02】_续

2、题目:从很多无序的数中(姑且假定各不相等),选出其中最大的K个数。

解法五、

思路:

1、采用快排的分治思想,首先取无序数中一随机数,将无序数分割成1、2两部分,其中第1部分数为小于该随机数集合,第2部分数为大于该随机数集合;

2、若恰好第1部分的数(加该随机数)个数为K,则直接返回前K个数即为所求;若第1部分的数个数大于K,则递归对查找第1部分数中最大K个数;若第1部分数个数小于K,则递归查找第2部分数中最大的K – length个数,length为第1部分数个数;

该算法时间复杂度为O(n * log n),同快排一样,该排序算法依赖于随机数的选取,具有不稳定性。

计算:

1、对整个数组进行分割算法(简单可直接取第一个数为分割随机数);

2、若分割后,第1部分数个数为K – 1,则数组前K个数即为所求;若分割后,第1部分数个数小于K – 1,则递归查找对第2部分数中K – split个最大数;若分割后,第1部分数大于K – 1,则递归查找第1部分数中K个最大数;

代码:

    private int partition(int[] arr, int begin, int end) {
        int key = begin, tmp;
        for(int low = begin, high = end; low < high; ) {
            if(arr[low] < arr[high]) {
                tmp = arr[low];               //swap arr[low] and arr[high]
                arr[low] = arr[high];
                arr[high] = tmp;
                
                if(key == low) {
                    low++;
                    key = high;
                } else {
                    high--;
                    key = low;
                }
            } else {
                if(key == low) {
                    high--;
                } else {
                    low++;
                }
            }
        }
        
        return key;
    }
    public void topK4(int []arr, int begin, int end, int k) {
        int split = partition(arr, begin, end);
        
        if((split - begin + 1) == k) {
            return;
        } else if(split - begin + 1 < k) {
            topK4(arr, split + 1, end, k - (split - begin) - 1);
        } else {
            topK4(arr, 0, split - 1, k);
        }

    }

思路:采用多路归并的思路,先将无序数划分成M等分,并对每等分内的数进行排序(可简单采用快排,其时间复杂度为Q * log Q,其中Q为每等分内数的个数),然后采用败者树进行归并排序,从每等分数中取出最大数作为叶节点进行归并排序,将节点与父节点进行比较,loser留在父节点,winner可继续进行更高层级比较;

计算:

1、对无序数进行M等分的划分;

2、依次取出每等分数中最大数,作为败者树叶节点进行sift up,对winner节点进行输出,并从该胜者节点所在的等分中取出目前最大数替换winner,直到输出的winner节点个数为K;

    public class LoseTree {
        
        private int[] branches;
        private int[] nodes;
        
        public void getNumFromBuffer(List<Integer> buffer, int bufferIndex) throws Exception {    //get number
            if(buffer.size() == 0) {
                throw new Exception("the buffer is null");
            }
            
            branches[bufferIndex] = buffer.remove(0);
        }
        
        public int competitionBranch(int branchIndex) {
            int father = (nodes.length + branchIndex - 1) / 2;
            while(father >= 0) {
                if(branches[nodes[father]] > branches[branchIndex]) {                      //swap the nodes[father] and the branchIndex
                    int tmp = nodes[father];
                    nodes[father] = branchIndex;
                    branchIndex = tmp;
                }
                
                if(father == 0) break; 
                else father = (father - 1) / 2;
            }
            
            return branchIndex;
        }
        
        public int getBranch(int branchIndex) {
            return branches[branchIndex];
        }
        
        public int init(List<Integer>[] buffers) throws Exception {
            branches = new int[buffers.length];               
            
            for(int i = 0; i < branches.length; i++) {     
                getNumFromBuffer(buffers[i], i);
            }
            
            nodes = new int[branches.length - 1];
            
            int max = -1;
            for(int i = 0; i < branches.length; i++) {     
                if(max < branches[i]) { max = i; }
            }
            for(int i = 0; i < nodes.length; i++) {        
                nodes[i] = max;
            }
            
            int winnerIndex = 0;                         
            for(int i = 0; i < nodes.length; i++) {
                winnerIndex = competitionBranch(i);
            }
            
            return winnerIndex;
        }
        
        public LoseTree() {

        }
        
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes"})
    public List<Integer>[] createBuffer(int[] arr, int k) {         
        
        List[] buffers = arr.length % k == 0 ? new List[arr.length / k] : new List[arr.length / k + 1];
        for(int i = 0; i < buffers.length; i++) {      
            buffers[i] = new ArrayList();
        }
        
        for(int i = 0; i < arr.length; i++) {      
            buffers[i / k].add(arr[i]);
        }
        
        int addition = arr.length % k;              
        if(addition != 0) {
            int end = arr.length / k;
            for(int i = addition; i < k; i++) {
                buffers[end].add(0);
            }
        }
        
        for(int i = 0; i < buffers.length; i++) {      
            Collections.sort(buffers[i], Collections.reverseOrder());
        }
        
        return buffers;
    }
    
    public List<Integer> topK(int []arr, int k) throws Exception {
        List<Integer>[] buffers = createBuffer(arr, k);          
        
        if(buffers.length == 1) {                  
            return buffers[0];
        }
        
        LoseTree loseTree = new LoseTree();
        int winnerIndex = loseTree.init(buffers);       
        
        List<Integer> topKArr = new ArrayList<Integer>();
        for(int i = 0; i < k - 1; i++) {
            winnerIndex = loseTree.competitionBranch(winnerIndex);      
            topKArr.add(loseTree.getBranch(winnerIndex));
            loseTree.getNumFromBuffer(buffers[winnerIndex], winnerIndex);       
        }
        winnerIndex = loseTree.competitionBranch(winnerIndex);
        topKArr.add(loseTree.getBranch(winnerIndex));
        
        return topKArr;
    }

 

posted @ 2013-01-12 00:11  @小小鸟@  阅读(1310)  评论(2编辑  收藏  举报