查询无序列表中第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)"); } } }
以下是部分输出结果:
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)
....
可明显看出该方法的优势。