• 検索結果がありません。

¥¢¥ë¥´¥ê¥º¥à¥¤¥ó¥È¥í¥À¥¯¥·¥ç¥ó ÎØ¹Ö #1

N/A
N/A
Protected

Academic year: 2021

シェア "¥¢¥ë¥´¥ê¥º¥à¥¤¥ó¥È¥í¥À¥¯¥·¥ç¥ó ÎØ¹Ö #1"

Copied!
70
0
0

読み込み中.... (全文を見る)

全文

(1)

アルゴリズムイントロダクショ

ン 輪講

#1

id:motemen

(2)

よろしくお願いします

(3)

今日やること

1 - 3章 イントロダクション アルゴリズムの設計・解析 挿入ソート マージソート オーダーの記法 関数の増加

(4)

教科書の構成

1 - 5章 数学的基礎 6 - 9章 ソート 10 章 - 14 章 データ構造 1巻ここまで 2 巻以降 さらに高度な話題へ

(5)

この本で学べること

アルゴリズムそのもの

アルゴリズムの設計と解析の技法 データ構造

(6)

アルゴリズムを学ぶ理由

計算機が無限の速度を持ち、メモリがただで 手に入っても アルゴリズムが停止するか? 正しい答えが得られるか? 現実に、計算時間・メモリの面で効率の良い アルゴリズムが必要 新たな問題に取り組む足掛かりが欲しい なんかかっこいい

(7)

アルゴリズムとは

”ある値または値の集合を入力とし、ある値 または値の集合を出力する、明確に定義され た計算手続き” 疑似コード ”明確に定義された計算問題を解くための 道具” 問題の例: ソーティング問題 入力 n 個の数の列 < a1, a2, . . . , an > 出力 a01 ≤ a02 ≤ · · · ≤ a0n であるよう な入力列の並べ替え < a01, a02, . . . , a0n >

(8)
(9)

最初のアルゴリズム

:

挿入ソート

トランプで手札を並べ替えるときに普通やる 方法

Google: ”insertion sort” site:youtube.com

ソートされていないカードから 1枚ずつ、 ソートされているカードの適切な位置に挿入 していく

(10)

挿入ソート

:

疑似コード

procedure Insertion-Sort(A) for j ← 2 to length[A]

do key ← A[j]

i ← j − 1

while i > 0 and A[i] > key do A[i + 1] ← A[i]

i ← i − 1 A[i + 1] ← key 配列は 1 ベース

代入は

length[A]というのは JS や Ruby の A.length の意 (構造体のメンバへのアクセス)

(11)

アルゴリズムができたらすることは?

アルゴリズムの正当性の検証 アルゴリズムは終了するか? アリゴリズムは正しい答えを返すか? アルゴリズムの性能の評価 どのくらいの時間がかかるのか

(12)

挿入ソート

:

正当性

アルゴリズムの正当性を検証するために、 「ループ不変式」を使用 ループ前・中・後で常に成り立つ条件に注目 することで、ループの意味を検証する 1回目のループで成り立つ n回目のループで成り立つなら、n + 1 回目でも 成り立つ → ループ終了時に成り立つ

(13)

挿入ソート

:

正当性

アルゴリズムの正当性を検証するために、 「ループ不変式」を使用 ループ前・中・後で常に成り立つ条件に注目 することで、ループの意味を検証する 1回目のループで成り立つ n回目のループで成り立つなら、n + 1 回目でも 成り立つ → ループ終了時に成り立つ

(14)

不変式が満たすべき

3

つの性質

初期条件 ループの実行開始直前で成り立つ ループ内条件 ループ中のある繰り返しの直前で 成り立つなら、つぎの繰り返しの直前 でも成り立つ 終了時条件 ループが終了したとき、アルゴリズ ムの正当性の証明を手助けする性質が 得られる 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(15)

不変式が満たすべき

3

つの性質

初期条件 ループの実行開始直前で成り立つ ループ内条件 ループ中のある繰り返しの直前で 成り立つなら、つぎの繰り返しの直前 でも成り立つ 終了時条件 ループが終了したとき、アルゴリズ ムの正当性の証明を手助けする性質が 得られる 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(16)

不変式が満たすべき

3

つの性質

初期条件 A[1..j − 1]A[1] だけからなる配列 なのでソート済み ループ内条件 ループ中のある繰り返しの直前で 成り立つなら、つぎの繰り返しの直前 でも成り立つ 終了時条件 ループが終了したとき、アルゴリズ ムの正当性の証明を手助けする性質が 得られる 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(17)

不変式が満たすべき

3

つの性質

初期条件 A[1..j − 1]A[1] だけからなる配列 なのでソート済み ループ内条件 A[j] が正しい場所に挿入されてい るので OK (while の解析はここではし ない) 終了時条件 ループが終了したとき、アルゴリズ ムの正当性の証明を手助けする性質が 得られる 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(18)

不変式が満たすべき

3

つの性質

初期条件 A[1..j − 1]A[1] だけからなる配列 なのでソート済み ループ内条件 A[j] が正しい場所に挿入されてい るので OK (while の解析はここではし ない) 終了時条件 A[1..j − 1]A 全体なので配列は ソートできた アルゴリズムは正 しい 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(19)

不変式が満たすべき

3

つの性質

初期条件 A[1..j − 1]A[1] だけからなる配列 なのでソート済み ループ内条件 A[j] が正しい場所に挿入されてい るので OK (while の解析はここではし ない) 終了時条件 A[1..j − 1]A 全体なので配列は ソートできた アルゴリズムは正 しい 不変式: for 文の最初で、部分列 A[1..j − 1] はソートされている

(20)

アルゴリズムの実行にかかる時間

実行にかかる時間は… 入力に依存 始めからソートされていると早い 逆順にソートされていると一番遅い → 通常、最悪の場合を考慮 入力のサイズに依存 → 実行にかかる時間を入力のサイズの関数 T (n)で表す

(21)

Insertion-Sort

の実行時間を計算

各ステップの実行回数を計算 (n = length[A]) for j ← 2 to length[A] n

do key ← A[j] n− 1

i ← j − 1 n− 1

while i > 0 and A[i] > key ∑nj=2tj do A[i + 1] ← A[i]nj=2(tj − 1) i ← i − 1 ∑nj=2(tj − 1) A[i + 1]← key n− 1 tj というのは挿入する場所を探す回数 (ループ毎 に別々) ループの判定文は本体より 1 回多く実行される

(22)

Insertion-Sort

の実行時間を計算

各行の実行コストに、それぞれの実行回数を 掛けたものの和を計算 もともとソート済みのとき (最良) while は 1 回しか実行されない: tj = 1 T (n) = an + b の形になる 逆順にソートされていたとき (最悪) while が i = 0 になるまで実行される: tj = j T (n) = an2 + bn + c の形になる

(23)

Insertion-Sort

の実行時間を計算

各行の実行コストに、それぞれの実行回数を 掛けたものの和を計算 もともとソート済みのとき (最良) while は 1 回しか実行されない: tj = 1 T (n) = an + b の形になる 逆順にソートされていたとき (最悪) while が i = 0 になるまで実行される: tj = j T (n) = an2 + bn + c の形になる

(24)

Insertion-Sort

の実行時間を計算

各行の実行コストに、それぞれの実行回数を 掛けたものの和を計算 もともとソート済みのとき (最良) while は 1 回しか実行されない: tj = 1 T (n) = an + b の形になる 逆順にソートされていたとき (最悪) while が i = 0 になるまで実行される: tj = j T (n) = an2+ bn + c の形になる

(25)

アルゴリズムの実行時間の評価

本当に興味があるのは、実行時間の「増加の オーダー」 (増加率) なので、主要でない項を削ぎ落とす 挿入ソートの最悪実行時間は T (n) = an2+ bn + c 挿入ソートの最良実行時間は T (n) = an + b Θ については後で

(26)

アルゴリズムの実行時間の評価

本当に興味があるのは、実行時間の「増加の オーダー」 (増加率) なので、主要でない項を削ぎ落とす 挿入ソートの最悪実行時間は T (n) = an2+ bn + c 挿入ソートの最良実行時間は T (n) = an + b Θ については後で

(27)

アルゴリズムの実行時間の評価

本当に興味があるのは、実行時間の「増加の オーダー」 (増加率) なので、主要でない項を削ぎ落とす 挿入ソートの最悪実行時間は T (n) = an2+ bn + c = Θ(n2) 挿入ソートの最良実行時間は T (n) = an + b = Θ(n) Θ については後で

(28)

アルゴリズムの実行時間の評価

本当に興味があるのは、実行時間の「増加の オーダー」 (増加率) なので、主要でない項を削ぎ落とす 挿入ソートの最悪実行時間は T (n) = an2+ bn + c = Θ(n2) 挿入ソートの最良実行時間は T (n) = an + b = Θ(n) Θ については後で

(29)
(30)

2

のアルゴリズム

:

マージソート

マージすべき配列を 2つに分け、それぞれに マージソートをかけた後マージする

Google: ”merge sort” site:youtube.com

分割統治法 (divide-and-conquer)

ちなみに挿入ソートは 逐次添加法 (incremental approach)

(31)

分割統治法

問題を部分問題に分解し、その解を組み合わ せる

再帰的なアルゴリズムの多くが分割統治法に 基づいている

(32)

分割統治の

3

段階

分割 問題をいくつかの部分問題に分割する 統治 部分問題を再帰的に解く ただし、部分問題のサイズが十分小さ い場合は直接的な方法で解く 結合 部分問題の解を組み合わせて解を得る

(33)

マージソートでの各段階

分割 入力の配列を半分ずつに分割する 統治 マージソートを用いて部分列を再帰的 にソートする ただし、入力の長さが 1 であれば何も しない 結合 ソートされた部分列をマージすること で解を得る

(34)

マージ

2つのソートされた配列をマージして 1つの ソートされた配列にする 「2つの配列の先頭から小さい方を取る」を 繰り返す: Θ(n) その際、配列の最後に ∞ を追加しておくと便利 (番兵)

(35)

マージ

2つのソートされた配列をマージして 1つの ソートされた配列にする 「2つの配列の先頭から小さい方を取る」を 繰り返す: Θ(n) その際、配列の最後に ∞ を追加しておくと便利 (番兵)

(36)

マージ

2つのソートされた配列をマージして 1つの ソートされた配列にする 「2つの配列の先頭から小さい方を取る」を 繰り返す: Θ(n) その際、配列の最後に ∞ を追加しておくと便利 (番兵)

(37)

マージ

(

疑似コード

)

procedure Merge(A, p, q, r) n1 ← q − p + 1 n2 ← r − q for i← 1 to n1 do L[i]← A[p + i − 1] for j← 1 to n2 do R[j]← A[q + j] L[n1+ 1]← ∞ R[n2+ 1]← ∞ i← 1 j ← 1 for k← p to r do if L[i]≤ R[j]

then A[k]← L[i]

i← i + 1

else A[k]← R[j]

(38)

手続き

Merge

の正当性

ループ不変式を以下のようにする A[p..k− 1] には、L と R の要素中で小さい方 から k− p 個がソートされて入っている L[i] と R[j] は、L と R でまだ A に書き戻さ れていない要素のなかでそれぞれ最小

(39)

マージソート

Merge-Sort(A, p, r) 先の Merge 手続きを利用して A[p..r] を ソート p≤ r ならソート済み (0 か 1 要素) なので何も しない 分割: dn/2e 要素の A[p..q] と bn/2c 要素の A[q + 1..r]に分割

(40)

マージソート

Merge-Sort(A, p, r) 先の Merge 手続きを利用して A[p..r] を ソート p≤ r ならソート済み (0 か 1 要素) なので何も しない 分割: dn/2e 要素の A[p..q] と bn/2c 要素の A[q + 1..r]に分割

(41)

マージソート

Merge-Sort(A, p, r) 先の Merge 手続きを利用して A[p..r] を ソート p≤ r ならソート済み (0 か 1 要素) なので何も しない 分割: dn/2e 要素の A[p..q] と bn/2c 要素の A[q + 1..r]に分割

(42)

マージソート

(

疑似コード

)

配列 A の添字 p から r までをソートする procedure Merge-Sort(A, p, r) if p < r then q ← b(p + r)/2c Merge-Sort(A, p, q) Merge-Sort(A, q + 1, r) Merge(A, p, q, r)

(43)

分割統治アルゴリズムの実行時間

実行時間を T (n) として… 問題のサイズ n が小さいとき 定数時間しかかからない (何もしない) T (n) = Θ(1) 問題を a 個の部分問題に分割し、サイズを 1/b にしたとき T (n) = aT (n/b) + D(n) + C(n) D(n): 分割にかかる時間 C(n): 結合にかかる時間

(44)

マージソートの実行時間

分割 bn/2c を計算するだけなので D(n) = Θ(1) 統治 問題を 2 個に分割し、サイズが 1/2 に なるので a = b = 2, 2T (n/2) 結合 Merge には Θ(n) 時間かかるので C(n) = Θ(n) なので T (n) = { Θ(1) if n = 1 2T (n/2) + Θ(1) + Θ(n) if n > 1

(45)

マージソートの実行時間

(46)

マージソートの実行時間

T(n)

(47)

マージソートの実行時間

T(n/2) cn

(48)

マージソートの実行時間

T(n/2) cn

T(n/2)

(49)

マージソートの実行時間

cn/2 cn cn/2 T(n/4) T(n/4) T(n/4) T(n/4)

(50)

マージソートの実行時間

cn/2 cn cn/2 T(n/4) T(n/4) T(n/4) T(n/4) T (n/4) = 2T (n/8) + cn/4, . . .

(51)

マージソートの実行時間

cn/2 cn cn/2 T(n/4) T(n/4) T(n/4) T(n/4) c c c c

(52)

マージソートの実行時間

cn/2 cn cn/2 × 2 = cn cn/2 cn/4 cn/4 cn/4 × 4 = cn cn/4 cn/4 c c c × n = cn c c

(53)

マージソートの実行時間

cn/2 cn cn/2 × 2 = cn cn/2 cn/4 cn/4 cn/4 × 4 = cn cn/4 cn/4 c c c × n = cn c c 各段階が cn, 木の深さは log2n なので T (n) = cn log2n

(54)

log

2

n

って

2log2n = n 大雑把に言うと「n を表すのに必要なビッ ト数」 n に対して増え方が遅い log2256 = 8 log265536 = 16 log24294967296 = 32 マージソートは挿入ソートより高速

(55)

log

2

n

って

2log2n = n 大雑把に言うと「n を表すのに必要なビッ ト数」 n に対して増え方が遅い log2256 = 8 log265536 = 16 log24294967296 = 32 マージソートは挿入ソートより高速

(56)

log

2

n

って

2log2n = n 大雑把に言うと「n を表すのに必要なビッ ト数」 n に対して増え方が遅い log2256 = 8 log265536 = 16 log24294967296 = 32 マージソートは挿入ソートより高速

(57)
(58)

関数の増加のオーダーを測る

アルゴリズムの実行時間 T (n) の評価 nが増加したときにどのくらいのスピードで増 加するかに興味がある 定数部分には興味がない アルゴリズムの「漸近的」効率を調べる 漸近記号 Θ, O, Ω, . . . の導入

(59)

関数の増加のオーダーを測る

アルゴリズムの実行時間 T (n) の評価 nが増加したときにどのくらいのスピードで増 加するかに興味がある 定数部分には興味がない アルゴリズムの「漸近的」効率を調べる 漸近記号 Θ, O, Ω, . . . の導入

(60)

関数の増加のオーダーを測る

アルゴリズムの実行時間 T (n) の評価 nが増加したときにどのくらいのスピードで増 加するかに興味がある 定数部分には興味がない アルゴリズムの「漸近的」効率を調べる 漸近記号 Θ, O, Ω, . . . の導入

(61)

Θ-

記法

f (n) = Θ(g(n)) ⇐⇒ すべての n ≥ n0に対して 0 ≤ c1g(n)≤ f(n) ≤ c2g(n) であるような正の定数 c1, c2および n0が存在する 関数の漸近的な増え方を (上下から) 押さ える 挿入ソートの実行時間は Θ(n2) ではない 最悪時の実行時間は Θ(n2) ここでの = の使い方は 濫用 なので注意

(62)

O-

記法

f (n) = O(g(n)) ⇐⇒ すべての n ≥ n0に対して 0≤ f(n) ≤ cg(n) であるような正の定数 c および n0が存在する 関数の漸近的な増え方を (上から) 押さえる 挿入ソートの実行時間は O(n2)

(63)

Ω-

記法

f (n) = Ω(g(n)) ⇐⇒ すべての n ≥ n0に対して 0≤ cg(n) ≤ f(n) であるような正の定数 c および n0が存在する 関数の漸近的な増え方を (下から) 押さえる

(64)

o-

記法、

ω-

記法

f (n) = o(g(n)) ⇐⇒ 任意の定数 c > 0 に対してある定数 n0 > 0が存在して、 すべての n ≥ n0に対して 0≤ f(n) ≤ cg(n) である 「漸近的にタイトでない」上界 ω はこの反対

(65)
(66)

関数の増え方

log(x) vs x vs x2 vs x3 vs 2x 0..5 0 20 40 60 80 100 120 140 1 1.5 2 2.5 3 3.5 4 4.5 5 log(x) x x*x x*x*x 2**x

(67)

関数の増え方

log(x) vs x vs x2 vs x3 vs 2x 10..20 0 200000 400000 600000 800000 1e+06 1.2e+06 6 8 10 12 14 16 18 20 log(x) x x*x x*x*x 2**x

(68)

関数の増え方

log(x) vs x vs x2 vs x3 vs 2x 10..20 0 200000 400000 600000 800000 1e+06 1.2e+06 6 8 10 12 14 16 18 20 log(x) x x*x x*x*x 2**x 指数関数ヤバイ

(69)

オーダーに対する簡単な感覚

O(n!) >> O(kn) >> (越えられない壁) >> O(nk) > . . .

O(n3) > O(n2) > O(n log n) > O(n) > O(log n) >

(70)

まとめ

アルゴリズムに入門 挿入ソート・マージソート アルゴリズムの正当性 アルゴリズムの実行時間 オーダー表記

参照

関連したドキュメント

わからない その他 がん検診を受けても見落としがあると思っているから がん検診そのものを知らないから

この数字は 2021 年末と比較すると約 40%の減少となっています。しかしひと月当たりの攻撃 件数を見てみると、 2022 年 1 月は 149 件であったのが 2022 年 3

この条約において領有権が不明確 になってしまったのは、北海道の北

て当期の損金の額に算入することができるか否かなどが争われた事件におい

「カキが一番おいしいのは 2 月。 『海のミルク』と言われるくらい、ミネラルが豊富だか らおいしい。今年は気候の影響で 40~50kg

注意: 条件付き MRI 対応と記載されたすべての製品が、すべての国及び地域で条件付き MRI 対応 機器として承認されているわけではありません。 Confirm Rx ICM

・条例第 37 条・第 62 条において、軽微なものなど規則で定める変更については、届出が不要とされ、その具 体的な要件が規則に定められている(規則第

№3 の 3 か所において、№3 において現況において環境基準を上回っている場所でございま した。ですので、№3 においては騒音レベルの増加が、昼間で