查找N个数中第K大的数
這里消耗的時間就是排序用的時間,用快速排序則為:O( N log N )
代碼:
/*** 先排序后獲取* @return** Date :2012-7-4* Author :GongQiang*/public int sortThenGet( int k ){Collections.sort( list );return list.get( list.size() - k );}方法二:構造一個 K 長度的數組,將前K位數復制過來并排序(降序)。然后依次將 K+1 到 N 位的數比較并插入 K 長度的數組中。返回最后一個即可。
這時間度為:O( N*K ) 如果 K = N/2 ?則復雜度為 O( N*N )
代碼:
/*** 先取出前K個數排序,再從后面依次插入* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int kSortThenCompare( int k ){List<Integer> result = new ArrayList<Integer>( k );for( int i=0 ; i<k ; i++ ){result.add( list.get(i) );}//前K位數,按照從大到小排序Collections.sort( result, new Comparator<Integer>(){public int compare(Integer o1, Integer o2) {if( o1 > o2 ){return -1;}if( o1< o2 ){return 1;}return 0;}});// 后 K+1 位數與前面的有序數組比較,插入適當的位置for( int i=k ; i<list.size() ; i++ ){int j = k-1;while( j>=0 && list.get(i) > result.get(j) ){j--;}if( 0<=j && j<k-1 && list.get(i) < result.get(j) ){result.add( j+1, list.get(i) );}else if( j==-1 ){ //結束條件是 j==-1result.add( 0, list.get(i) );}}return result.get( k-1 );}方法三:將 N 個數構造成一個“大堆”,然后刪除堆的根 K 次,最后一次即為結果。
?構造堆的最壞用時:O( N )
每次刪除根用時:O( log N )
則中的運行時間為: O( N + k*log N )
如果 K = O( ?N/ log N ) ,則總共用時就是構造堆的時間,即 O( N )
如果 K 很大,則總時間為 O( K* log N)
如果 K = N/2,則總時間為Θ( N*log N )
代碼:
/*** 先構建一個堆,然后獲取* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int buildHeapThenGet( int k ){PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( NUMBER_COUNT, new Comparator<Integer>(){ //這里是取第K大的元素,因而要改變排序規則public int compare(Integer o1, Integer o2) {if( o1 > o2 ){return -1;}if( o1< o2 ){return 1;}return 0;}});for( int i=0 ; i<list.size() ; i++ ){heapQueue.add( list.get(i) );}int result=0;for( int i=0 ; i<k ; i++ ){result = heapQueue.remove();}return result;}方法四:思路和方法二一樣,只不過用堆來實現。
構造堆的時間:O( K )
處理每個其余元素的時間:O( 1 )
檢測是否進入堆的時間:O( log K )
總時間:O( K + (N-K)*log K ) = O( N* log K )
該算法找出中位數的時間界面:Θ( N*log N )
注意:這里使用優先隊列提供的堆來操作,這樣
檢測的時間為O( log K )
刪除的時間為O( log K )
插入的時間為O( log K )
所以,這里的代碼時間復雜度比單純在堆上操作要多很多。
代碼:
/*** 前K個數構造一個堆,然后進行比較插入* @param k* @return** Date :2012-7-4* Author :GongQiang*/public int heapOfFistKThenSert( int k ){PriorityQueue<Integer> heapQueue = new PriorityQueue<Integer>( k );for( int i=0 ; i<k ; i++ ){heapQueue.add( list.get(i) );}for( int j = k ; j<list.size() ; j++ ){int queueLength = k;int flag = 0;while( queueLength >0 ){if( heapQueue.peek() < list.get(j) ){flag =1;break;}queueLength--;}if( flag == 1 ){heapQueue.poll();heapQueue.offer( list.get(j) );}}return heapQueue.peek();}四種算法在 10 萬個數值中,查找第100大,1000大,10000大實際用時 先排序在獲取: 用時間:69547064, 100大數:99903985 用時間:64447309, 1000大數:98963233 用時間:63601693, 10000大數:89862625先排序前K個數,然后插入,最后獲取: 用時間:14299865, 100大數:99903985 用時間:94025432, 1000大數:98963233 用時間:4053122244, 10000大數:89857698先構建一個堆,然后獲取: 用時間:29191262, 100大數:99903985 用時間:11743673, 1000大數:98963233 用時間:21491442, 10000大數:89862625先構建一個堆(前K個數),依次比較插入,最后獲取: 用時間:199040953, 100大數:99903985 用時間:1786736869, 1000大數:98963233 用時間:11739682175, 10000大數:89862625
可以看出,方法三最優。
方法五:隨機選擇(參考快速排序的思想)
/*** 隨機選擇* @param list* @param start* @param end* @param i* @return** Date :2012-10-25* Author :GongQiang*/int randomSelect( List<Integer> list, int start, int end, int i ){if( start == end ){return list.get(start);}int q = randomPartition(list, start, end);int k = end - q + 1;if( i == k ){return list.get( q );}else if( i<k ){return randomSelect(list, q+1, end, i);}else{return randomSelect(list, start, q-1, i-k);}}private int randomPartition( List<Integer> list, int start, int end ){int i = (int)(random.nextFloat()*( end-start )) + start;swap( list, i, end );return partition(list, start, end);}private int partition( List<Integer> list, int start, int end ){int temp = list.get(end);int i = start - 1;for( int j=start; j<end; j++ ){if( list.get(j) <= temp ){i++;swap( list, i, j);}}swap( list, i+1, end);return i+1;}private void swap( List<Integer> list, int i, int j ){int temp = list.get(i);list.set(i, list.get(j));list.set(j, temp);}運行性能比較(一百萬中查詢):
先排序在獲取: 用時間:1073446509, 100大數:99991468 用時間:1086298487, 1000大數:99897550 用時間:995448554, 10000大數:98988059 用時間:996302124, 550000大數:45011888先構建一個堆,然后獲取: 用時間:98659237, 100大數:99991468 用時間:92088339, 1000大數:99897550 用時間:114273553, 10000大數:98988059 用時間:1590825451, 550000大數:45011888隨機選擇 用時間:113330378, 100大數:99991468 用時間:121606562, 1000大數:99897550 用時間:123834509, 10000大數:98988059 用時間:231643029, 550000大數:45011888可以看出,【隨機選擇】性能很穩定,而且較優!
總結
以上是生活随笔為你收集整理的查找N个数中第K大的数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts2中ActionContex
- 下一篇: 计算机科学中的逻辑学术,简述逻辑学在计算