目標 良いアルゴリズムが欲い !! 既に、悪い(かもしれない)アルゴリズム !! 「虱潰し」はある !! -> 時間計算量が小さいアルゴリズムを「良い」 # 速いのが嬉しい では、どうやって、高速にするか ? 「情報量(精度他)」と「計算時間量」は交換できる 例 リーダページから、単語 hello があるかどうかを 探す 頭から、単語を一つずつ調べる => リーダのページの単語数が計算量 辞書から単語 hello があるかどうかを 探す 頭から、単語を一つずつ調べる => 辞書の登録ワード数が計算量 !! 実際は、そうしない 辞書の単語が、順に並んでいる 順序の性質 x < y & y < z -> x < z hello を探す 今開いたページ google -> もっと、後ろページ idea -> もっと前のページ この「順序」の性質を利用した考え [問題] 辞書の見出し語を探す 辞書の単語は、1 page に一つ 見出し語は、アルファベット順 辞書のページは 1 〜 N とする 与えられた見出し語のあるページを探す [解法] 最初は求める語句は 1 〜 N の間にある M = ( 1 + N ) / 2 ; 丁度半分のページを 開く。 もし、M page 目の見出し語と、探したい 語が同じなら、「発見した」=>終了 そうでない場合 語の順を比較して、探したい語が 後ろならば、 次は、M と N の間 そうでないならば 次は 1 と N の間 を探す。 例 N = 11 1 a 2 bee 3 cat 4 hello 5 job 6 knot 7 pool 8 quize 9 set 10 rat 11 zoo 1 〜 11 a) (1 + 11)/2 -> 6 -> knot > hello 1 〜 6 b) (1+6)/2 -> 3 -> cat < hello 3 〜 6 c) (3+6)/2 -> 4 -> hell = hell : 発見 N -> N/2 -> N/4 -> .. > N/(2^k)=1 N = 2^k k = log_2 N 回で発見できる N | 2^10 = 1024 '=, 1000 順序をしらない o(N) | 1000 順序をしっている o(log_2 N) | 10 二分法 与えらえた解の範囲を、現時点で情報から 半分にする方法があれば、それを使って、 範囲を狭めてゆくやり方 平方根を求める場合に、どうやって高速化するか ? 実は(幸い..)ここでも二分法が使える 方程式の解は、 区間 [l.u] の幅 ( u - l ) がε以下になった場合 その中点とする f(x)=x^2-a=0 の解を、区間 [l,u] の中から探す 場合に、どうやって区間の幅を半分にするか ? # l < u # f(l) < 0 < f(u) # -> f(x) が連続なので、中間値の定理より # 区間 [l,u] の中に f(x)=0 の解が存在する # 次のようにする if ( u - l < ε ) { 答をみつけた } else { m = ( l + u )/2 ( m は、l と u の中点 ) /* f(m) >= 0 か f(m) < 0 のどちらか */ if ( f(m) >= 0 ) { u = m; /* 解は区間 [l,m] の中 */ } else { l = m; /* 解は区間 [m,u] の中 */ } /* いずれにせよ、区間は半分になる */