回 1-3 道 1 数と論理と計算量
計算量は、
読み終えたら入れ子の
この頁の流れ
ループの
データが 増えると、 時間は 何倍になるのか
時間が
名簿から
答えは、
この
計算量は どう 数えるのか
計算量は、
なぜ 時間ではなく 回数を 数えるのか
時間は
MIT の
ループの 形ごとの 回った回数
ループの
| ループの形 | 回った回数 | n = 10 | n = 1000 |
|---|---|---|---|
1 重 (for i in range(n)) | n | 10 | 1000 |
2 重 (内側も range(n)) | n × n | 100 | 1000000 |
三角形 (内側が range(i)) | n(n − 1) / 2 | 45 | 499500 |
半分にn = n // 2) | log2 n の | 3 | 9 |
表の
2 重の
三角形のrange(i) なので、
半分に
O 記法は 何を 残し、 何を 落とすのか
O 記法 (Big-O、
三角形の
- 一番速く
伸びる 項は n² / 2 なので、 − n / 2 を落とす - 係数の
1 / 2 を落とす - 残った
n² を O(n²) と書く
ですから、
よく 出る 5 つの O
よく
| O | n = 10 | n = 100 | n = 1000 | n = 10000 |
|---|---|---|---|---|
| O(1) | 1 | 1 | 1 | 1 |
| O(log n) | 3 | 6 | 9 | 13 |
| O(n) | 10 | 100 | 1,000 | 10,000 |
| O(n log n) | 30 | 600 | 9,000 | 130,000 |
| O(n²) | 100 | 10,000 | 1,000,000 | 100,000,000 |
O(1) は、
O(log n) の
O(n log n) の
図の
動かして確かめる
どのc += 1 を
1 本目は、
動かす ループの形ごとに回った回数を数える
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
n = 3
1重 3
2重 9
三角 3
半分 1
n = 10
1重 10
2重 100
三角 45
半分 3
n = 100
1重 100
2重 10000
三角 4950
半分 6
n = 1000
1重 1000
2重 1000000
三角 499500
半分 9n = 3 の
2 本目は、
動かす n を 2 倍にして倍率を見る
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
n = 100 → 200
1重 100 → 200 2.00倍
2重 10000 → 40000 4.00倍
三角 4950 → 19900 4.02倍
半分 6 → 7 +1回
n = 200 → 400
1重 200 → 400 2.00倍
2重 40000 → 160000 4.00倍
三角 19900 → 79800 4.01倍
半分 7 → 8 +1回
n = 400 → 800
1重 400 → 800 2.00倍
2重 160000 → 640000 4.00倍
三角 79800 → 319600 4.01倍
半分 8 → 9 +1回1 重は
3 本目は、
動かす 5 つの O を並べる
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
n = 10
O(1) 1
O(log n) 3
O(n) 10
O(n log n) 30
O(n²) 100
n = 100
O(1) 1
O(log n) 6
O(n) 100
O(n log n) 600
O(n²) 10,000
n = 1000
O(1) 1
O(log n) 9
O(n) 1,000
O(n log n) 9,000
O(n²) 1,000,000
n = 10000
O(1) 1
O(log n) 13
O(n) 10,000
O(n log n) 130,000
O(n²) 100,000,000計算量の 見積もりは どこで 外れるのか
O 記法は
O が 同じでも、 係数で 回数が変わる
O(n) どうしでも、
小さい n では O(n²) の 方が 少ない こともある
1 個に
動かす 係数の大きい O(n) と O(n²)
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
n=10 A 1,000 B 100 B
n=50 A 5,000 B 2,500 B
n=100 A 10,000 B 10,000 =
n=200 A 20,000 B 40,000 A
n=1000 A 100,000 B 1,000,000 An = 10 と
O が
最悪と 平均は違う
同じin は、x in l を
in とc += 1 は、== で
動かす in と同じ順で比べた回数
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
先頭を探す 1
真ん中 501
末尾 1000
無い物 1000
平均 500.51000 個の
テストで
ループの 中に、 隠れた ループがある
リストの in、文字列の in や index、文字列の + は、
次のuniq は、in とbuild は、+ で
動かす 隠れたループを数える
▶ 実行ボタンを押すと結果がここに表示されます
実行すると、次の通りに出ます
n = 10
比べた回数 45
写した字数 55
n = 100
比べた回数 4950
写した字数 5050
n = 1000
比べた回数 499500
写した字数 500500uniq の
build の
直し方は、set にします。set や dict の
計算量は 仕事で どう 確かめるのか
仕事では、
- コードを
読むときは、 ループの 中にある in、index、+、sortを探す。 1 行でも 中で ループしているかを確かめる - 回った
回数を n の 式で 書き、 O に する。 三角形なら n(n − 1) / 2 で、 O(n²) - 試験では、
n と 2n で 回数か 時間を 出し、 倍率を 見る。 2 倍なら O(n)、 4 倍に 近いなら O(n²) を疑う
回数をuniq の
回数で O の形を固める試験
def test_uniq_grows_like_n2():
a = uniq(list(range(100)))
b = uniq(list(range(200)))
# 2 倍の n で約 4 倍なら n²
assert 3.9 < b / a < 4.1set に
関わる実例
Cloudflare の 正規表現の 障害 (2019年7月2日)
Cloudflare は
報告の.*.*=.* というx=x という; を足した .*.*=.*; では、x=x にx= の後ろに x を
崩れた
出典は Details of the Cloudflare outage on July 2, 2019 (Cloudflare 公式ブログ) です。
ハッシュの 衝突で サービスを 止める 攻撃 (2011年12月28日)
2011年12月28日、dict のように、
崩れたdict をdict のuniq と
勧告は、-R で
出典は oCERT-2011-003 multiple implementations denial-of-service via hash algorithm collision (oCERT) です。
よくある問い
計算量と 時間計算量は 同じですか
この
O(n²) の コードは 書いてはいけないのですか
書いてかまいません。
O(log n) の log の 底は何ですか
O 記法では
Python の sort の 計算量は どれくらいですか
Python のsort をsort すると、
O と Θ と Ω は 何が 違いますか
O は
確認クイズ
答えだと
1 問目
次のc += 1 は
三角形のループ
c = 0
for i in range(n):
for j in range(i):
c += 12 問目
回った
3 問目
n 個のin で
説明課題
次のc += 1 が
3 つのループ
# 1 つ目
for i in range(n):
c += 1
# 2 つ目
for i in range(n):
for j in range(n):
c += 1
# 3 つ目
for i in range(n):
for j in range(i):
c += 1自分の
この回の 先の一歩
件数が
もっと深く
この
一次資料
どれも
- Details of the Cloudflare outage on July 2, 2019 (Cloudflare 公式ブログ、英語)。2019年7月2日に
WAF の 規則の 正規表現が 大量の 後戻りで CPU を 使い 切った こと、 CPU が 100% 近く、 502 の エラー、 27 分止まったこと、 .*.*=.*がx=xに23 手、 .*.*=.*;が90 手と 5,353 手かかる こと、 正規表現の 道具に 計算量の 保証が 無かった こと、 守りが 作り直しで 外れていた こと、 試験が CPU の 使いすぎを 見ていなかったこと - oCERT-2011-003 multiple implementations denial-of-service via hash algorithm collision (oCERT、英語)。2011年12月28日の
勧告、 予測できる ハッシュの 衝突で CPU を 100% に でき数時間続く こと、 POST の 値の 数の 上限が 無いこと、 対象の 言語、 Python の 直した 版が ランダム化を 既定で切り -Rで入れる 形だったこと - Time complexity of operations on built-in types (Python 公式文書、英語)。リストの
x in lがO(n)、 dictのO(1) は 平均で ハッシュの 衝突が まれな 場合に 限り、 すべての 鍵が 同じハッシュなら O(n) に なる こと、 文字列を ループで つなぐと 全体の 長さに 対して 2 乗に なること、 setの探す操作が 平均で O(1)、 sortが最悪で O(n log n) で 並んだ 入力では 比べる 回数が O(n) の こと。 古い 住所 https://wiki.python.org/moin/TimeComplexity は この 頁へ 移ったと 案内しています - Introduction to Algorithms 6.006 Lecture 1 notes (MIT OpenCourseWare、
英語、 2020年春)。性能を 機械に よらない 形で 表すために 決まった 時間の 操作の 回数を 数える こと、 漸近的な 書き方では 定数の 係数と 次数の 低い項を 無視する こと、 O を 上の 押さえ、 Ω を 下の 押さえ、 Θ を ぴったりの 押さえとして 並べていること
