25
BFPRT algorithm MATSUURA Satoshi [email protected] 1 Blum-Floyd-Pratt-Rivest-Tarjan, 1973

BFPRT algorithm

Embed Size (px)

Citation preview

Page 1: BFPRT algorithm

BFPRT algorithm

MATSUURA Satoshi [email protected]

1

Blum-Floyd-Pratt-Rivest-Tarjan, 1973

Page 2: BFPRT algorithm

中央値ソートを復習しましょう

2

Page 3: BFPRT algorithm

3

中央値ソート7 2 8 0 6 3 5

中央値を探し、中央の要素とスワップ

6 7 83 2 0 5

7 2 8 5 6 3 0中央値より大きい左側の要素を、中央値以下の右側の要素とスワップ

中央値の左右で配列を分割し、再帰的に部分配列を整列させる

6 7 80 2 3 52つ、または3つの部分配列で上記処理が終わると、ソートが完了する。

(1つの部分配列の整列には意味が無い)

再帰的に整列させる部分配列のサイズがほぼ等しくなる(半分になっていく)ため、O(n log n)のコストと考えられる。

Page 4: BFPRT algorithm

そもそも中央値を求める方法は?

4

Page 5: BFPRT algorithm

5

7 2 8 0 6 3 50 1 2 3 4 5 6

中央値(3番目に小さい数)を探すことが目的

partition関数

int partition(array, left, right, pivotIndex)

・配列の特定範囲(left, right)をpivot要素を基準に2分割する。・前半はpivot要素以下の値に、後半はpivot要素より大きな値に分割する。・pivot要素 = array[pivotIndex]であり、left ≦ pivotIndex ≦ rightである。・返値は分割後のpivot要素の位置を表す。

? partition関数があったとしてどのように中央値が算出できるか? partition関数の実装はどのようなものが考えられるか

Page 6: BFPRT algorithm

partition関数の中身を見ていこう

6

Page 7: BFPRT algorithm

7

7 2 8 0 6 3 5

7 2 8 0 6 5 3

0 1 2 3 4 5 6

7 2 8 0 6 5 3

② 7 8 0 6 5 3

② 7 8 0 6 5 3

partition(0,6,5)開始5番目の要素を選ぶ

一番右側とスワップ(一時的な待避)

3以下の数を左側から探す

発見できたら左側からスワップ

3以下の数を継続して探す

② ⓪ 8 7 6 5 3発見できたら左側からスワップ

② ⓪ 8 7 6 5 33以下の数を探し終端まで到達

② ⓪ ③ 7 6 5 8発見できたら左側からスワップ

0 1 2 3 4 5 6

Page 8: BFPRT algorithm

8

7 2 8 0 6 3 50 1 2 3 4 5 6

② ⓪ ③ 7 6 5 8

初期状態

partition実行後

欲しい数  :3番目に小さな値(中央値)得られた情報:選択したpivot要素(3)は2番目の位置

② ⓪ ③ 7 6 5 8

pivot要素以下の数、ここでは3以下の要素で構成される

pivot要素より大きい数、ここでは3より大きな要素で構成される

0 1 2 3 4 5 6

partition(0,6,5)pivot位置を5番目と選ぶ

partition(0,6,5)の結果pivotは2番目の位置

pivot要素が3番目の位置であったなら、それが中央値であったのに残念、、、次は右側の配列の中で0番目に大きな数を探そう。つまりpartition(3,6,0)を実行しよう。

再帰的に追っていけば、いつかは見つかるはず。

Page 9: BFPRT algorithm

9

7 2 8 0 6 3 50 1 2 3 4 5 6

② ⓪ ③ ⑤ 6 8 7

初期状態

partition実行後

partition(0,6,6)pivot位置を6番目と選ぶ

partition(0,6,6)の結果pivotは3番目の位置

7 2 8 0 6 3 50 1 2 3 4 5 6

② ⓪ ③ 7 6 5 8

初期状態

partition実行後

partition(0,6,5)pivot位置を5番目と選ぶ

partition(0,6,5)の結果pivotは2番目の位置

7 2 8 0 6 3 50 1 2 3 4 5 6

⑤ ② ⓪ ⑥ ③ 7 8

初期状態

partition実行後

partition(0,6,0)pivot位置を0番目と選ぶ

partition(0,6,0)の結果pivotは5番目の位置

k = pの場合:得られたpivot要素が中央値

k > pの場合:[p+1, right]からk-p-1番目に小さな値が中央値となる。

[p+1, right]にpartitionを実行。

k < pの場合:[left, p-1]からk番目に小さな値が中央値となる。[left, p-1]にpartitionを実行。

k: 求めるべき中央値の位置(ここではk=3)p: 得られたpivot位置

Page 10: BFPRT algorithm

10

② ⓪ ③ 7 6 5 8

pivot要素以下の数、ここでは3以下の要素で構成される

pivot要素より大きい数、ここでは3より大きな要素で構成される

0 1 2 3 4 5 6

7 2 8 0 6 3 50 1 2 3 4 5 6

② ⓪ ③ 7 6 5 8

初期状態

partition実行後

partition(0,6,5)pivot位置を5番目と選ぶ

partition(0,6,5)の結果pivotは2番目の位置

partition実行後はpivotを基準に左側に小さな部分配列が、右側に大きな部分配列が出来た事を思いだそう。

*partition関数動作例(再掲)

1.partition関数を再帰的に実行2.中央値の発見3.発見したときにはすでに左側の部分配列は中央値以下に、  右側の部分配列は中央値より大きくなっている

すぐに下位の部分配列の整列に取りかかれる

*中央値ソートの手順

Page 11: BFPRT algorithm

中央値ソートも中央値の発見方法もわかった :)

11

Page 12: BFPRT algorithm

でも、partition実行時のpivot選択はどうするのか?

12

Page 13: BFPRT algorithm

13

partition関数のpivot選択pivotの選択は両端のいずれかから順に選択する方法、ランダムに選択する方法など多くの方法が考えられ、pivot選択方法が全体のパフォーマンスを決定する。

・pivotの選択を誤ると中央値を探すためにpartition関数を多く実行する必要がある・partition関数を1回実行した時のコストはO(n)・最悪時はpartition1回につき一要素しか絞り込めない時であり、n-1回partitionを実行する必要がある。つまり一回の中央値を得るコストがおよそn^2となる。一段下位の部分配列に関してもおよそ2 * (n / 2)^2のコストがかかる。コストの総和は2*n^2を越えないので、partition全体のコストはO(n^2)。このコストが支配的になり全体でもO(n^2)となる。

*最悪時のコスト

なんだか面倒な事になっている。クイックソート使った方が。。。

Page 14: BFPRT algorithm

pivot選択の失敗に引きずられて、

O(n^2)になるのは嫌だ。。

14

それ、BFPRTで出来るよ

Page 15: BFPRT algorithm

15

BFPRTアルゴリズム

・目的 真の中央値に近似した値をO(n)のコストで探す。

・概要 1.対象の配列を短い部分配列(オリジナルアルゴリズムでは5)に分割し、   それぞれの部分配列の中央値からなる配列を作る。 2.中央値からなる配列に1の手順を再帰的に適応し、1つになるまで   絞り込む。 3.最終的に得られた(中央値に近似した)1つの要素をpivotとして利用する。

Page 16: BFPRT algorithm

16

BFPRTアルゴリズムの手順23 7 9 81 17 11 34 39 44 28 3 72 54・・・ソート対象の配列

23

7

9

81

17

11

34

39

44

28

12

98

3

72

54

・・・5個の配列に分割し、

それぞれで中央値を求める

23

7

17

81

9

11

39

34

44

28

12

98

54

72

3

・・・

5417 34 ・・・

部分配列の中央値を集め、上記の手順を再帰的に繰り返す。つまり、5個の配列に分割し、それぞれで中央値を求め、中央値の集合で配列を作る。またその配列を...と繰り返す

34

最後に残った要素は真の中央値に近似した値となり、これをpivotして利用する

partition(array, left, right, 34)

Page 17: BFPRT algorithm

17

BFPRTのコスト

・5個の配列の中央値を得るために必要な数値比較の回数は8以下 (条件分岐のツリーを書いて確認してみてください)

・配列をnとすると部分配列の中央値の集合を得るためには 最悪時で(n/5) * 8 = 1.4nの数値比較が必要。

・中央値の集合は元の配列の1/5の長さになっているので、 BFPRT全体のコストは下記に示すようにO(n)となる。 8n/5 + 8n/(5^2) + 8n/(5^3) ・・・ < 8n/4 = 2n

Page 18: BFPRT algorithm

18

BRPRTで中央値の近似値がO(n)で求まることが分かった。

で、本当に中央値の近似値なの?

Page 19: BFPRT algorithm

19

中央値と部分配列の中央値群ソート対象の配列 23 7 9 81 17 11 34 39 44

7 9 11 17 23 34 39 44 81ソート済みの状態と真の中央値

7 9 11 17 23 34 39 44 81

A群 B群 C群

ソート済みの配列をA<B<Cとなるように3等分にグループ化する

ソート対象の配列を部分配列に分割

23 7 9 81 17 11 34 39 44

B A A C B A B C C

9

A

17

B

39

C

17

B

部分配列の中央値を求める

中央値群から中央値を求める

B群以外から最終的な要素が選択される事はあるのだろうか?

ここでは簡単のため部分配列長を”3”とする

Page 20: BFPRT algorithm

20

中央値と部分配列の中央値群

*中央値群にBが選択されない例

9個の要素からは必ずB群(中央値近辺1/3)の要素が選択される

・B群が最終的な要素に選択されない → 部分配列の中央値群にBを選択しない → できる限りBを含む部分配列を作りかつBが中央値にならない組み合わせを考える → AAB, BCCの組み合わせが一番適している → 残りの組み合わせがABCとなり中央値群にBが選択されてしまう → 最終的にB群の要素が選択される → 命題に矛盾する

23 7 9 81 39 4434 39 44

B A A C C CB C C

9

A

39

C

39

C

9 7 11

A A A

9

A

上記二つの例の様にBを選択しないためにはAAB、BCCの組み合わせが最適。AAB->A, BCC->Cが選択される。しかし残りの組み合わせ(ABC)で必ずBが選択され、結果的にBを選択せざる得ない。

Page 21: BFPRT algorithm

21

中央値と部分配列の中央値群・9個の要素から中央値群を取り出すと最低でも1つB群の要素を含む →9個の要素からは必ずB群(中央値近辺1/3)の要素が選択される。

 (一般化して長い配列を考えてみよう)・3つの部分配列を選択し、その9個の要素においてA, B, Cの数が等しい場合、 中央値群を選択すると最低でも1つのB群の要素を含む。・また数列全体において、A, B, Cの数は等しいため、全体の中央値群を選択すると 最低でも中央値群の1/3はB群の要素を含む。

A C C B A C A B C A A C B B A B C C A B A B B C A B C

C B B A B C A B B

B B B

B

A C C B A A A B C A A C B B A B A A C B C B B C C B C

C A B A B A C B C

B A C

B

ABC, ABC, ABCの様な部分配列の組が出来るとB群が選択されやすくなる

意図的にB群が選択されにくいようにしたケース。中央値群の1/3は常にB群が選択されている。

帰納的に、元の配列のB群(中央値近辺1/3)の要素が選択される

Page 22: BFPRT algorithm

22

部分配列の長さが「3」の時、中央値周辺の1/3の値が近似値として選ばれる事が分かった*。

*BFPRTオリジナルは「5」の部分配列長を持ちます。より精度の高い近似値が得られます。同じ要領で出来るので確認してみてください。

Page 23: BFPRT algorithm

23

つまり、最悪時でも配列を1/3と2/3の大きさで分割でき、1/2で分割する時と比べて最悪時で定数倍(2倍)*コストがかかる。→O(n log n)のコストが

保証される*等比級数の和で分割の深さを考える Σ(1/2)^n = 1 (n→∞) Σ(2/3)^n = 2 (n→∞)

Page 24: BFPRT algorithm

24

BFPRTまとめ

・中央値選択のコストをかけすぎてO(n^2)になるのを避けたい(最悪時)・元の配列を固定長の部分配列に分割し、各々の配列から中央値を取り出して、 中央値群を作成し、同様の操作を再帰的に繰り返して中央値の近似値を得る・近似値を得る過程はO(n)で求まる・部分配列長が3の時(オリジナルは5)、近似値は全配列をソートした場合の 中央1/3の要素から選択される。つまり最悪時でも1/3, 2/3分割が出来る。・分割過程は中央1/2で分割する場合の定数倍コストがかかる。・BFPRTを使ってソートを行う場合のコストはO(n log n)である。

Page 25: BFPRT algorithm

25

参考文献

アルゴリズム クイックリファレンス, George T. Heineman, Gary Pollice, Stanley Selkow (著), 黒川 利明, 黒川 洋(訳).4.3 中央値ソート, pp.74-86, オライリージャパン, 2010.