求兩個升序序列的中位數
阿新 • • 發佈:2019-01-07
這裡涉及到資料結構中順序表的實現、刪除、插入、查詢等知識,請檢視:資料結構 -> 線性表
問題描述:
一個長度為L (L>=1)的升序序列S,處在第[L/2]個位置的數稱為S的中位數。例如,若序列S1=(11, 13, 15, 17, 19),則S1的中位數是15,兩個序列的中位數是含它們所有元素的升序序列的中位數。例如,若S2= (2, 4,6,8, 20),則S1和S2的中位數是11。現在有兩個等長升序序列A和B,試設計一個在時間和空間兩方面都儘可能高效的演算法,找出兩個序列A和B的中位數。要求:
1) 給出演算法的基本設計思想。
2) 根據設計思想,釆用C或C++或Java語言描述演算法,關鍵之處給出註釋。
3) 說明你所設計演算法的時間複雜度和空間複雜度。
該題為2011年研究生考試計算機聯考真題。
問題解答:
(1)演算法的基本設計思想如下:
分別求兩個升序序列A、B的中位數,設為a和b,求序列A、B的中位數過程如下:
1) 若a=b,則a或b即為所求中位數,演算法結束。
2) 若a<b,則捨棄序列A中較小的一半,同時捨棄序列B中較大的一半,要求兩次捨棄的長度相等。
3) 若a>b,則捨棄序列A中較大的一半,同時捨棄序列B中較小的一半,要求兩次捨棄的長度相等。
在保留的兩個升序序列中,重複過程1)、2)、3),直到兩個序列中均只含一個元素時為止,較小者即為所求的中位數。
(2)本題程式碼如下:
int M_Search(int A[], int B[], int n) { int start1 = 0, end1 = n - 1, m1, start2 = 0, end2 = n - 1, m2; //分別表示序列A和B的首位數、末位數和中位數 while (start1 != end1 || start2 != end2) { m1 = (start1 + end1) / 2; m2 = (start2 + end2) / 2; if (A[m1] == B[m2]) return A[m1]; //滿足條件 1) if (A[m1]<B[m2]) // 滿足條件 2) { if ((start1 + end1) % 2 == 0) //若元素個數為奇數 { start1 = m1; //捨棄A中間點以前的部分且保留中間點 end2 = m2; //捨棄B中間點以後的部分且保留中間點 } else //元素個數為偶數 { start1 = m1 + 1; //捨棄A中間點及中間點以前部分 end2 = m2; //捨棄B中間點以後部分且保留中間點 } } else { //滿足條件3) if ((start2 + end2) % 2 == 0) //若元素個數為奇數 { end1 = m1; //捨棄A中間點以後的部分且保留中間點 start2 = m2; //捨棄B中間點以前的部分且保留中間點 } else //元素個數為偶數 { end1 = m1; //捨棄A中間點以後部分且保留中間點 start2 = m2 + 1; //捨棄B中間點及中間點以前部分 } } } return A[start1]<B[start2] ? A[start1] : B[start2]; }
(3)演算法的時間複雜度為O(log2n),空間複雜度為O(1)。