兩個等長升序序列找中位數


題目

   一個長度為 L 的升序序列 S,處在第個位置的數稱為 S 的中位數。例如,若序列 ,則  的中位數是 15,兩個序列的中位數是含他們所有元素的升序序列的中位數。例如,若 ,則  和  的中位數是 11。現在有兩個等長升序序列 A 和 B,試設計一個算法,找出兩個序列 A 和 B 的中位數。

分析

暴力

  把 A 和 B 混合到一起再找中位數。實現方法簡單且不為本篇文章討論重點,不再詳細敘述。

減治

  將升序序列左右兩邊同時減去相等個數的數字,中位數不變。

  令兩個升序序列 A , B 的中位數為 a , b,求解過程如下:

    ① 若 a = b,則 a 或 b 即為所求中位數。

    ② 若 a < b,則舍棄序列 A 中較小的一半,同時舍棄序列 B 中較大的一半,要求兩次舍棄的長度相等。

    ③ 若 a > b,則舍棄序列 A 中較大的一半,同時舍棄序列 B 中較小的一半,要求兩次舍棄的長度相等。

  在保留的兩個升序序列中,重復過程 ① ,② ,③,直到兩個序列中均只含一個元素時為止,較小者即為所求的中位數。 

① a = b

  a = b時,容易得到兩個序列在數軸上的大小關系,雖然左右兩邊並沒有絕對大小關系,但是中位數的選取只跟中間位置有關,所以並不影響。

② a != b

  a != b時,以 a < b 為例。

  對於奇數個數序列:

    因為中位數只與升序序列的位置有關,通過左圖中的有/無絕對大小關系可得 藍1,藍2,綠4,綠5 代表的四個數絕對不可能在中間位置(5),所以把他們刪去,即中位數的大小范圍為 [a , b] 。

  對於偶數個數序列:

    還是那句話因為中位數只與升序序列的位置有關,通過右圖中的有/無絕對大小關系可得 藍1,藍2,綠3,綠4 代表的四個數絕對不可能在中間位置(4),所以把他們刪去,即中位數的大小范圍為 ( a , b ]。

 

實現

int M_Search(int A[], int B[], int n) { int s1=0,d1=n-1,m1,s2=0,d2=n-2,m2;//A,B序列的首位數、中位數、末位數
    while (s1 != d1 || s2 != d2) { m1=(s1+d1)/2; m2=(s2+d2)/2; if (A[m1]==B[m2])             //當兩個中位數相等,即為所求中位數
            return A[m1]; else if (A[m1]<B[m2]) { if((s1+d1)%2==0)          //當元素個數為奇數
 { s1=m1;                //舍棄A中間點以前的部分且保留中間點
                d2=m2;                //舍棄B中間點以后的部分且保留中間點
 } else                      //當元素個數為偶數
 { s1=m1+1;              //舍棄A中間點及中間點以前的部分
                d2=m2;                //舍棄B中間點以后的部分且保留中間點
 } } else                          //同理
 { if ((s2+d2)%2==0) { d1=m1; s2=m2; } else { d1=m1; s2=m2+1; } } } return A[s1]<B[s2]?A[s1]:B[s2]; }


免責聲明!

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



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