mirror of
https://github.com/krahets/hello-algo.git
synced 2026-11-02 03:05:24 +08:00
* Retranslate the complete Japanese online edition from Chinese * Fit Japanese homepage labels and localize heading permalinks * Point Japanese contribution instructions to the Japanese preview * Replace locale conditionals with multilingual UI tables
56 lines
5.6 KiB
Markdown
56 lines
5.6 KiB
Markdown
# まとめ
|
||
|
||
### 要点の振り返り
|
||
|
||
**アルゴリズムの効率の評価**
|
||
|
||
- 時間効率と空間効率は、アルゴリズムの良し悪しを測る二つの主な基準です。
|
||
- 実測でも効率を評価できますが、測定環境の影響を除くのが難しく、大量の計算資源を使います。
|
||
- 計算量の解析は実測の欠点を補い、すべての実行環境に適用できる結果と、異なるデータ量での効率を示します。
|
||
|
||
**時間計算量**
|
||
|
||
- 時間計算量は、データ量の増加に伴う実行時間の増え方を測るもので、効率の評価に役立ちます。ただし、入力が小さい場合や計算量が同じ場合など、効率を正確に比較できないこともあります。
|
||
- 最悪時間計算量はビッグ $O$ 記法で表し、関数の漸近上界に対応します。$n$ が正の無限大に近づくときの、操作回数 $T(n)$ の増加のオーダーを表します。
|
||
- 時間計算量は、まず操作回数を数え、次に漸近上界を求める、という 2 段階で見積もります。
|
||
- 代表的な時間計算量を小さい順に並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$、$O(n!)$ などがあります。
|
||
- 計算量が一定ではなく、入力データの分布によって変わるアルゴリズムもあります。時間計算量には最悪・最良・平均があります。最良の場合を達成するには入力に厳しい条件が必要なため、最良時間計算量はほとんど使いません。
|
||
- 平均時間計算量はランダムな入力での実行効率を表し、実際の用途での性能に最も近いものです。求めるには、入力データの分布と、それらを総合した期待値を計算する必要があります。
|
||
|
||
**空間計算量**
|
||
|
||
- 空間計算量は時間計算量と同様に、データ量の増加に伴うメモリ使用量の増え方を測ります。
|
||
- 実行に関わるメモリ空間は、入力空間、一時空間、出力空間に分けられます。通常、入力空間は空間計算量に含めません。一時空間は、一時データ、スタックフレーム、命令の空間に分けられ、スタックフレームが計算量に影響するのは通常、再帰関数の場合だけです。
|
||
- 通常は最悪空間計算量だけに注目し、最悪の入力と最もメモリを使う時点での空間計算量を求めます。
|
||
- 代表的な空間計算量を小さい順に並べると、$O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$、$O(2^n)$ などがあります。
|
||
|
||
### Q & A
|
||
|
||
**Q**:末尾再帰の空間計算量は $O(1)$ ですか。
|
||
|
||
理論上、末尾再帰関数の空間計算量は $O(1)$ に最適化できます。ただし、ほとんどのプログラミング言語(Java、Python、C++、Go、C# など)は自動的な末尾再帰最適化に対応していないため、通常は $O(n)$ と考えます。
|
||
|
||
**Q**:関数とメソッドという用語には、どのような違いがありますか。
|
||
|
||
<u>関数(function)</u>は独立して実行でき、すべての引数を明示的に渡します。<u>メソッド(method)</u>はオブジェクトに関連付けられ、呼び出し元のオブジェクトが暗黙に渡されるため、クラスのインスタンスに含まれるデータを操作できます。
|
||
|
||
いくつかの代表的な言語で説明します。
|
||
|
||
- C は手続き型言語であり、オブジェクト指向の概念がないため、関数だけがあります。ただし、構造体(struct)を作ってオブジェクト指向を模倣でき、構造体に関連付けた関数が、ほかの言語のメソッドに相当します。
|
||
- Java と C# はオブジェクト指向言語で、コードのまとまり(メソッド)は通常、クラスの一部です。静的メソッドはクラスに結び付けられ、特定のインスタンス変数にアクセスできないため、関数に似た動作をします。
|
||
- C++ と Python は、手続き型(関数)とオブジェクト指向(メソッド)の両方をサポートします。
|
||
|
||
**Q**:「代表的な空間計算量」の図は、使用する空間の絶対量を示していますか。
|
||
|
||
いいえ。図が示すのは空間計算量、つまり増え方の傾向であり、空間の絶対量ではありません。
|
||
|
||
$n = 8$ とすると、曲線の値が対応する関数と一致しないことに気づくかもしれません。各曲線には、見やすい範囲に収めるための定数項を加えているためです。
|
||
|
||
実際には、各手法の計算量の「定数項」がわからないことが多く、通常、計算量だけで $n = 8$ のときの最良の解法を選ぶことはできません。一方、$n = 8^5$ なら増加の傾向が支配的になるため、選びやすくなります。
|
||
|
||
**Q** 実際の用途に応じて、時間や空間を犠牲にして設計することはありますか。
|
||
|
||
実際の用途では、空間を使って時間を節約する選択が多く見られます。たとえばデータベースのインデックスでは、B+ 木やハッシュインデックスに大量のメモリを使うことで、$O(\log n)$、さらには $O(1)$ の高速な検索を実現します。
|
||
|
||
空間資源が貴重な場面では、時間を使って空間を節約することもあります。たとえば組み込み開発ではメモリが貴重なため、ハッシュテーブルを使わず、配列の順次探索を選ぶ場合があります。メモリを節約できる代わりに、探索は遅くなります。
|