2013-05-06 29 views
2

當我被分配到寫算法,從無序組數字的發現K-階數一門功課的中位數。作爲一種方法,已經提出了算法median of medians選擇:中位數

不幸的是,我學嘗試已經失敗。如果有人發現錯誤 - 請糾正我。

private int find(int[] A, int size, int k) { 
    if (size <= 10) { 
     sort(A, 0, size); 
     return A[k]; 
    } else { 
     int[] M = new int[size/5]; 
     for (int i = 0; i < size/5; i++) { 
      sort(A, i*5, (i+1) * 5); 
      M[i] = A[i*5 + 2]; 
     } 

     int m = find(M, M.length, M.length/2); 

     int[] aMinus = new int[size]; 
     int aMinusIndex = 0; 
     int[] aEqual = new int[size]; 
     int aEqualIndex = 0; 
     int[] aPlus = new int[size]; 
     int aPlusIndex = 0; 
     for (int j = 0; j < size; j++) { 
      if (A[j] < m) { 
       aMinus[aMinusIndex++] = A[j]; 
      } else if (A[j] == m) { 
       aEqual[aEqualIndex++] = A[j]; 
      } else { 
       aPlus[aPlusIndex++] = A[j]; 
      } 
     } 

     if (aMinusIndex <= k) { 
      return find(aMinus, aMinusIndex, k); 
     } else if (aMinusIndex + aEqualIndex <= k) { 
      return m; 
     } else { 
      return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex); 
     } 
    } 
} 

private void sort(int[] t, int begin, int end) { //simple insertion sort 
    for (int i = begin; i < end; i++) { 
     int j = i; 
     int element = t[i]; 
     while ((j > begin) && (t[j - 1] > element)) { 
      t[j] = t[j - 1]; 
      j--; 
     } 
     t[j] = element; 
    } 
} 

我跑的測試是把數字{200,199,198,...,1),並得到有序排列的第一個數字。我越來越:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -13 

這是在return A[k]行拋出,因爲遞歸調用,:

return find(aPlus, aPlusIndex, k - aMinusIndex - aEqualIndex); 
+0

您是否嘗試過在調試器中運行你的代碼? – 2013-05-06 21:06:47

+0

你確定你的輸入和輸出關係嗎? – 2013-05-06 21:51:14

回答

0

我不知道你到底是什麼問題,但你絕對應該是這樣做:

sort(A, i*5, (i+1) * 5); 

此外,你不應該做這麼多的複製,當你這樣做時你不會獲得任何性能。該算法應該在適當的位置完成。

檢查這個維基百科:Selection algorithm

+0

爲什麼我不應該排序子陣列? 我不能在維基百科上看到算法的任何遞歸。我很感激一個主張如何避免複製的原因,我必須承認它產生了相當大的負擔。 – yusuf 2013-05-06 21:49:44

2

的遞歸步驟您的分支邏輯是倒退。你試圖找到第k個最小的數,你已經發現有aMinusIndex數小於m,aEqualIndex等於m,並且aPlusIndex大於m。

如果aMinusIndex> = k,而不是aMinusIndex < = k等,則應該在aMinus中搜索。 (通過查看極端情況可以很容易地看到:假設零數小於m,那麼顯然你不應該在空數組中尋找任何東西,但是因爲0 < = k,所以你會這樣)。

+0

你是對的條件。然而,隨着變化,我最終得到了奇怪的結果。第8,第13,...數,對於哪個算法返回0. – yusuf 2013-05-06 21:48:57

0

我明白,這是家庭作業,讓您的選擇可能會受到限制,但我沒有看到中位數的中位數是如何那麼有用這裏。只需使用標準算法對整個數組進行排序,然後選擇第k個元素。中位數的中位數有助於找到一個非常好的支點。對於長度爲200的數據,您不會節省太多時間。

據我所知,您不能準確地獲得中位數,百分位數或第k個元素,而不能最終排序整個輸入數組。使用子集產生估計值。如果這是錯誤的,我真的很想知道,正如我最近研究的代碼中的數百萬數組中的百分位數!

p.s.這可能是因爲我不完全理解你的代碼...

+0

排序比這個算法漸近地慢,留下執行問題。 – tmyklebu 2013-05-06 22:38:29

+0

@tmykebu你有一個很好的參考這個M M算法?我想更多地瞭解它。謝謝。順便說一句,在]維基百科文章中,我發現(http://en.wikipedia.org/wiki/Selection_algorithm#Linear_general_selection_algorithm_-_Median_of_Medians_)支持我:「雖然這種方法優化得不錯,它通常在實踐中預期的線性算法優於隨機選擇樞軸[需要引證]。「 – user949300 2013-05-06 22:43:07

+0

@ user93400:這是在CLRS。是的,隨機抽樣會做得更好。然而,這個中位數的中位數技巧仍然大大優於排序。 – tmyklebu 2013-05-06 22:58:25