查询无序列表中第K小元素

当需要在无需列表中寻找第k小的元素时,一个显然的方法是将所有数据进行排序,然后检索k个元素。这种方法的运行时间为O(n log(n))。

无序列表调用分区函数将自身分解成两个子表,其长度为i和n-i。第一个列表中的第一个i元素(不一定排序),当i与k进行比较时需在第一或第二个子列表中搜索元素。

使用findMinK(ArrayList<Integer>array, int k, int i, int r)实现,同时使用下面testframe代码测试。在函数中可增加全局变量cmpcnt,在列表中利用分区函数交换元素时计数。

对findMinK函数的实现,利用了快排的思想:

先从n个元素中找一个任意分界点,设为m,假设m在列表中的位置是i

先从n个元素中随便寻找一个数m作为分界点,m在列表中的位置为i

当 i = k时,m就是我们要寻找的第k小的数;

当 i > k时,我们就从1~i-1中查找;

当 i < k时,就从i+1~n中查找。

下面是代码实现:

package disorder_List;

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Random; 
  
public class TestDisorder { 
    static public int cmpcnt = 0; 
  
    public static void main(String[] args) { 
        testFramework(); 
        
    
    } 
  
    public static int partion(ArrayList<Integer> A,int low,int high){
        int pivotkey=A.get(low);
        
        while(low<high){
            while(low<high&&A.get(high)>=pivotkey)
                high--;
            A.set(low, A.get(high));
           cmpcnt++;
            while(low<high&& A.get(low)<pivotkey)
                low++;
            A.set(high, A.get(low));
            cmpcnt++;
        }
        cmpcnt++;
        A.set(low, pivotkey);
        return low;
    }
    
    public static int findMinK(ArrayList<Integer> array, int k, int l, int r) { 
        // Implement here 
        if(l<=r){
            int pivotloc=partion(array, l, r);
            if(pivotloc==k-1){
                return array.get(pivotloc);
            }
            else if(pivotloc<(k-1)){
                return findMinK(array, k,pivotloc+1,r);
            }
            else{
                return findMinK(array, k,l,pivotloc-1);
            }
        }else
        {
            return -1;
        }
        
    } 
  
    public static int findMinK(ArrayList<Integer> array, int k){ 
        Collections.sort(array); 
        return array.get(k-1); 
    } 
  
    private static void testFramework() { 
        ArrayList<Integer> a = new ArrayList<Integer>(); 
        for (int j=2;j<8;j++){ 
            a.clear(); 
           
            for (int i=0;i<(int)Math.pow(10, j);i++){ 
                a.add(i); 
            } 
            System.out.println("nn"+a.size()+" Elementsnn"); 
            double slow=0; 
            double fast=0; 
            
            for (int i = 0; i < 2; i++) { 
                cmpcnt = 0; 
                Collections.shuffle(a); 
               
                int k = (int)(Math.random()*(Math.pow(10, j)-1))+1; 
  
                System.out.println("test run number: " + i + " find: " + k); 
  
                long start = System.currentTimeMillis(); 
                int resulta = findMinK(a, k, 0, a.size()-1); 
                long end = System.currentTimeMillis(); 
                long smarttime=(end-start); 
                fast = fast + smarttime; 
                System.out.println("SMART ALGO t --- time in ms: " + smarttime + " comparisons: " 
                        + cmpcnt); 
                start = System.currentTimeMillis(); 
                int resultb=findMinK(a, k); 
                end = System.currentTimeMillis(); 
                long slowtime = (end-start); 
                System.out.println("WITH SORTING t --- time in ms: " + slowtime); 
            
                slow = slow + slowtime; 
            }            
            System.out.println("sorting (="+slow+"ms) is " +slow/fast + " times slower than smart algo (="+fast+"ms)"); 
        } 
    }    
} 
View Code

以下是部分输出结果:

sorting (=3.0ms) is 3.0 times slower than smart algo (=1.0ms)

sorting (=24.0ms) is 12.0 times slower than smart algo (=2.0ms)

sorting (=41.0ms) is 8.2 times slower than smart algo (=5.0ms)

sorting (=401.0ms) is 4.773809523809524 times slower than smart algo (=84.0ms)

....

可明显看出该方法的优势。

 

 

posted @ 2014-04-11 16:20  smile_tina  阅读(1320)  评论(1编辑  收藏  举报