algorithms introduction 9章
TRANSCRIPT
Introduction to Algorithms : Chapter 9
Medians and Order Statistics
選択問題
• 入力: n 個の異なる数字の集合Aと整数i ( 1 ≦ i ≦ n )
• 出力: Aのi番目に大きい要素x (x ∈ A)
簡単な方法
• ソートしてi番目の要素を取り出す
• O(nlogn) (マージソート等)
より良い方法• 実は O(n) で可能
• この後のスライド
1. 最大/最小値探索問題 (O(n))
2. 期待実行時間がO(n)のアルゴリズム
3. 最悪実行時間がO(n)のアルゴリズム
最大値/最小値探査問題• 最小値(or 最大値) を見つける場合→ n-1 回の比較が必要 [証] 1回の比較で1つずつ最小値の候補が減る→ O(n)
同時に最大値/最小値を探索• 最大値/最小値を両方見つけたい
• 単純にやると 2n-2 の比較
• 比較回数を減らす方法
1. 暫定の最大値/最小値を記憶しておく
2. まずまだ比較をおこなっていない2つの要素を比較
3. その結果大きい方を暫定の最大値,小さい方を暫定の最小値と比較
4. 比較回数は3回ですむ
同時に最大値/最小値を探索• 暫定の最大値/最小値の初期値は
• 要素数が奇数の場合: 一番目の要素を暫定の最大値/最小値とする → 3*floor(n/2)の比較
• 要素数が偶数の場合: 一番目と二番目の要素を比較し暫定の最大値/最小値を決定 → 3(n-2)/2 の比較
• 結局最大の比較回数はせいぜい floor(3n/2)→Θ(n)
より一般的な問題• A[p..r] から i番目の要素を取り出す
• クイックソート的な感じ
• 期待計算量はΘ(n), 最悪の場合Θ(n^2)
RANDOMIZED_PARTITION()
• ピボットの選択をランダムに行い分割する→ 入力データの分布によらず計算量の期待値が計算できる
期待計算量を求める• 最悪の場合: p-r-1のサブ配列を再帰的に処理 → Θ(n^2)
for(i = n;i > 0;i ̶) { for (j = 0; j < i; j++) {分割処理} }
• 実際に興味があるのは期待計算量 T(n) をRANDOMIZED-SELECT()の計算量だとしてE[T(n)]を求める
• X_k = I{サブ配列A[p..q] が k個の要素を持つ}
• E[X_k] = 1/n
期待計算量を求める• X_k = 1 となる k は唯一つのみ
• X_k = 1 のときサブ配列は k-1とn-kの要素を持つ
期待計算量を求める
• ここで,nが偶数: T([n/2])からT(n-1)は2回ずつ現れるnが奇数: T([n/2])が1回,他はT(n-1)が2回現れる
期待計算量を求める• 以上より,
• ここで,E[T(n)] ≦ cn を仮定 (c:定数)さらに nがある定数以下なら T(n) = O(1)と考えO(n)の上限をan (a:定数) で表すとする
期待計算量を求める
nが十分大きいときcn/4-c/2-an ≧0となればいい
期待計算量を求める
• cn/4 - c/2 - an ≧ 0 → n ≧ 2c/(c-4a) になれば良い
• このためには c > 4a となる必要がある
• T(n)が n < 2c/(c-4a) において O(1)とすれば E[T(n)] = O(n)
より良い方法 : SELECT• 最悪の場合の計算量が O(n)のアルゴリズム: SELECT アルゴリズム (Median of Medians)
1. n個の要素をceil(n/5)のグループに分ける
2. それぞれのグループの中央値を挿入ソートで求める
3. 2. で求めた中央値集合の中央値をSELECTアルゴルズムを再帰的に適用して求める (求めた値をxとする)
4. 3. で求めた中央値の中央値を使って入力配列を分割する 具体的にはkが小さい方の配列の要素数+1の数だとすると,xはk番目に小さい数でn-kの要素が大きい方の配列に入る
5. i == k なら x を返す.i < k なら SELECTアルゴリズムを小さい方の配列に適用,i > k ならSELECTアルゴリズムを大きい方の配列に適用
SELECTアルゴリズム
要素の分割図(矢印: 大きい→小さい)
SELECTアルゴリズムでは,良いピボットを選択する
最悪計算量の見積もり
• step 2 で求めた複数の中央値の半分はxと同じか大きい矢印 ceil(n/5) / 2 個のグループのうち最低でも3つの要素はxより小さい (要素が5個未満の最後のグループを除く).従って,xより大きい要素の数はせいぜい n- n/5/2*3 = 7n/10同じように 3n/10-6 個の要素がxより小さい → step 5で最悪の場合 7n/10 + 6 の要素に対して再帰的に処理をおこなう
最悪計算量の見積もり• step1,2,4: O(n)
• step3: T(ceil(n/5))
• step5: T(7n/10 + 6)
• 要素数が140以下のきはO(1)であると仮定すると(140 の起源についてはこの後示す)
最悪計算量の見積もり• T(n) ≦ cn (c:大きな定数)と仮定さらに O(n) の上限 をan (a:定数) とする-cn/10 + 7c + an ≦ 0 なら T(n) ≦ cn → c ≧ 10a(n/(n-70)) (n≧70のとき)n ≧ 140 としたので n/(n-70) ≦ 2, c ≧ 20aのように選べば上の等式を満たす実際には n は 70より大きければ,cを適切に選べば等式は成り立つ
最悪計算量の見積もり• 再掲
• ポイントは,n/5 + 7n/10 = 9n/10 < n であること
• 分割数 x = 5 以外の場合は? → とりあえず xは奇数 (偶数だと中央値に偏りが生じる)
• x = 3 の場合:T(n) ≦ T(n/3) + T(2n/3) + O(n) → n/3+2n/3 = n これは×(中央値の中央値x より最低でも n/3/2*2 の要素が大きい → 最大でもn - n/3/2*2 = 2n/3の要素がxより小さい)
• x = 7,9,11,… でも良いが,そうすると分割にかかる時間が増える
まとめ• SELECTアルゴリズムを使えば最悪計算量がO(n)でn個の要素からi番目の要素が取得可能
• SELECTアルゴリズムでは入力の分布に対して何らかの仮定がいらない
• ソートを使う場合 Ω(n log n), asymptotically inefficient