Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 91 additions & 1 deletion docs/02algorithms/05order/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,96 @@ $n = 2$ 程度なら計算量の差はほとんどありませんが、$n$ の
| $10^9$ | 1 | 30 | - | - | - | - | - | - |
| $10^{10}$ | 1 | 34 | - | - | - | - | - | - |

## 計算量の求め方

実際に、いくつかの計算量を求めてみましょう。

<ViewSource path="/order/example1.ipynb" />

このプログラムは for 文で $n$ 回繰り返されるので、計算量は $O(n)$ です。

<ViewSource path="/order/example2.ipynb" />

このプログラムは for 文で $n^2$ 回繰り返されるので、計算量は $O(n^2)$ です。

<ViewSource path="/order/example3.ipynb" />

このプログラムは一見すると $n$ 回の繰り返しに見えますが、`g` 関数の方にも繰り返しがあり、$n^2$ 回の繰り返しになるので、計算量は $O(n^2)$ です。

<ViewSource path="/order/example4.ipynb" />

このプログラムは for 文で $n^2+n=O(n)$ 回繰り返されるので、計算量は $O(n^2)$ です。

<ViewSource path="/recursion/recurrence_relation_rec.ipynb" />

再帰関数は少し難しいですがプログラムの流れを追っていくと次のようになっているので、$n$ 回処理が実行され、計算量は $O(n)$ です。

```mermaid
flowchart LR
n["a(n)"] --> n-1["a(n-1)"]
n-1["a(n-1)"] -...-> 3["a(3)"]
3["a(3)"] --> 2["a(2)"]
2["a(2)"] --> 1["a(1)"]
```

<ViewSource path="/recursion/fib.ipynb" />

これは、難しいです。図を書くとわかりやすいです。計算量は、この図のノードの数になります。それぞれのノードから、二本の矢印が出ていて、最大 $n$ 回で `fib(0)` まで到達するので、計算量は $O(2^n)$ よりも小さくなります。

```mermaid
flowchart
A["fib(n)"] --> B["fib(n-1)"]
A --> C["fib(n-2)"]
B --> D["fib(n-2)"]
B --> E["fib(n-3)"]
C --> F["fib(n-3)"]
C --> G["fib(n-4)"]
D --> H["fib(n-3)"]
D --> I["fib(n-4)"]
E --> J["fib(n-4)"]
E --> K["fib(n-5)"]
F --> L["fib(n-4)"]
F --> M["fib(n-5)"]
H --> N["fib(n-4)"]
H --> O["fib(n-5)"]
```

数学的に、求めてみます。

計算量を $T(n)$ とします。

$$
\begin{align*}
T(n) &= T(n-1) + T(n-2) \\
&<2T(n-1) \quad (\because T(n-2)<T(n-1)) \\
&<2^2T(n-2) \\
&<\cdots \\
&<2^nT(0) \\
&=2^n \\
\end{align*}
$$

これで、計算量が $O(2^n)$ よりも小さいことが証明できました。

:::info

計算量は $O(2^n)$ よりも小さくなると言いましたが、実際に厳密に計算すると $O\left(\left(\frac{1+\sqrt{5}}{2}\right)^n\right)$ になります。($\frac{1+\sqrt{5}}{2}\simeq 1.618$)

ランダウの記号は、$n$ が十分大きい時、ある関数以下に抑えられるという意味なので、$O(2^n)$ と言っても間違いではないとは思います。

これは、漸化式を解けば求まります。

$$
\begin{align*}
T(n) &= T(n-1) + T(n-2) \\
&\cdots \\
\therefore T(n) &= \frac{1}{\sqrt{5}}\left\{\left(\frac{1 + \sqrt{5}}{2}\right)^n - \left(\frac{1 - \sqrt{5}}{2}\right)^n\right\} \\
&= O\left(\left(\frac{1+\sqrt{5}}{2}\right)^n\right)
\end{align*}
$$

:::

## 練習問題 1

次のプログラムの計算量を求めてください。
Expand All @@ -93,7 +183,7 @@ for 文の中が `n` 回繰り返されるので、$O(n)$ となります。

</Answer>

## 練習問題 2
## 練習問題 3

次のプログラムの計算量を求めてください。

Expand Down
14 changes: 7 additions & 7 deletions static/order/example1.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@
{
"metadata": {},
"source": [
"def calc_sum(n):\n",
" s = 0\n",
" for i in range(1, n + 1):\n",
" s += i\n",
" return s\n",
"def f(n):\n",
" cnt = 0\n",
" for _ in range(n):\n",
" cnt += 1\n",
" return cnt\n",
"\n",
"\n",
"print(calc_sum(10))"
"print(f(100))"
],
"cell_type": "code",
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"55\n"
"100\n"
]
}
],
Expand Down
16 changes: 8 additions & 8 deletions static/order/example2.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@
{
"metadata": {},
"source": [
"def calc_sum_square(n):\n",
" s = 0\n",
" for i in range(1, n + 1):\n",
" for j in range(1, n + 1):\n",
" s += i * j\n",
" return s\n",
"def f(n):\n",
" cnt = 0\n",
" for _ in range(n):\n",
" for _ in range(n):\n",
" cnt += 1\n",
" return cnt\n",
"\n",
"\n",
"print(calc_sum_square(10))"
"print(f(100))"
],
"cell_type": "code",
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"3025\n"
"10000\n"
]
}
],
Expand Down
37 changes: 37 additions & 0 deletions static/order/example3.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"nbformat": 4,
"nbformat_minor": 2,
"metadata": {},
"cells": [
{
"metadata": {},
"source": [
"def g(cnt, n):\n",
" for _ in range(n):\n",
" cnt += 1\n",
" return cnt\n",
"\n",
"\n",
"def f(n):\n",
" cnt = 0\n",
" for _ in range(n):\n",
" cnt = g(cnt, n)\n",
" return cnt\n",
"\n",
"\n",
"print(f(100))"
],
"cell_type": "code",
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"10000\n"
]
}
],
"execution_count": null
}
]
}
34 changes: 34 additions & 0 deletions static/order/example4.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"nbformat": 4,
"nbformat_minor": 2,
"metadata": {},
"cells": [
{
"metadata": {},
"source": [
"def f(n):\n",
" cnt = 0\n",
" for _ in range(n):\n",
" for _ in range(n):\n",
" cnt += 1\n",
" for _ in range(n):\n",
" cnt += 1\n",
" return cnt\n",
"\n",
"\n",
"print(f(100))"
],
"cell_type": "code",
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"10100\n"
]
}
],
"execution_count": null
}
]
}