無序數組的中位數


參考:http://mp.weixin.qq.com/s?__biz=MjM5ODIzNDQ3Mw%3D%3D&idx=1&mid=2649965551&scene=0&sn=bc769eb3fbd2f4075c58524f4cc8332d

中位數,就是數組排序后處於數組最中間的那個元素。說來有些麻煩,如果數組長度是奇數,最中間就是位置為(n+1)/2的那個元素。如果是偶數呢,標准的定義是位置為n/2和位置為n/2+1的兩個元素的和除以2的結果,有些復雜。為了解答的方便,我們假設數組長度暫且都為奇數吧。 

面試時,大家是不是經常被問到,怎么求一個無序數組(長度為n)的中位數?

不假思索的算法是,首先將數組排序,然后直接從排序數組中找出中位數。這個算法的復雜度是O(nlogn),就是排序的復雜度。當然,答案是有了,但不會impress面試官的:)。but it is ok, 如果你能寫出代碼。

排序代碼

 1 public void sort(int arr[],int low,int high)
 2 {
 3     int l=low;
 4     int h=high;
 5     int povit=arr[low];
 6 
 7     while(l<h)
 8     {
 9         while(l<h&&arr[h]>=povit) h--;
10         if(l<h){
11             int temp=arr[h];
12             arr[h]=arr[l];
13             arr[l]=temp;
14             l++;
15         }
16 
17         while(l<h&&arr[l]<=povit) l++;
18 
19         if(l<h){
20             int temp=arr[h];
21             arr[h]=arr[l];
22             arr[l]=temp;
23             h--;
24         }
25     }
26     
27     if(l>low) sort(arr,low,l-1);
28     if(l<high) sort(arr,l+1,high);
29 }

另外一個優化的快速算法是快速中位數算法,類似於快速排序,采用的是分而治之的思想。基本思路是:任意挑一個元素,以該元素為支點,將數組分成兩部分,左部分是小於等於支點的,右部分是大於支點的。如果你的運氣爆棚,左部分正好是(n-1)/2個元素,那么支點的那個數就是中位數。否則的話,相信你知道怎么推理了。寫出沒有bug的代碼還是需要一點點功力的。作為家庭作業好了。

代碼

 1 public static double median2(int[] array){
 2     if(array==null || array.length==0) return 0;
 3     int left = 0;
 4     int right = array.length-1;
 5     int midIndex = right >> 1;
 6     int index = -1;
 7     while(index != midIndex){
 8         index = partition(array, left, right);
 9         if(index < midIndex) left = index + 1;
10         else if (index > midIndex) right = index - 1;
11         else break;
12     }
13     return array[index];
14 }
15 
16 public static int partition(int[] array, int left, int right){
17     if(left > right) return -1;
18     int pos = right;
19     right--;
20     while(left <= right){
21         while(left<pos && array[left]<=array[pos]) left++;
22         while(right>left && array[right]>array[pos]) right--;
23         if(left >= right) break;
24         swap(array, left, right);
25     }
26 
27     swap(array, left, pos);
28     return left;
29 }

 

這里,給大家介紹一個讓人眼前一亮的算法,至少,看着很美妙,可以細細品味。算法的核心是使用最小堆(heap),你想到了嗎?

首先將數組的前(n+1)/2個元素建立一個最小堆。

然后,對於下一個元素,和堆頂的元素比較,如果小於等於,丟棄之,接着看下一個元素。如果大於,則用該元素取代堆頂,再調整堆,接着看下一個元素。重復這個步驟,直到數組為空。

當數組都遍歷完了,那么,堆頂的元素即是中位數。

可以看出,長度為(n+1)/2的最小堆是解決方案的精華之處。

代碼

 1 public static double median(int[] array){
 2     int heapSize = array.length/2 + 1;
 3     PriorityQueue<Integer> heap = new PriorityQueue<>(heapSize);
 4     for(int i=0; i<heapSize; i++){
 5         heap.add(array[i]);
 6     }
 7     for(int i=heapSize; i<array.length; i++){
 8         if(heap.peek()<array[i]){
 9             heap.poll();
10             heap.add(array[i]);
11         }
12     }
13     if(array.length % 2 == 1){
14         return (double)heap.peek();
15     }
16     else{
17         return (double)(heap.poll()+heap.peek())/2.0;
18     }
19 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM