データ構造とアルゴリズム
第三回 (2008年10月
10日)
抽象データ型とデータ構造、スタック、キューなど
http://www.sw.it.aoyama.ac.jp/2008/DA/lecture3.html
Martin J. Dürst
duerst@it.aoyama.ac.jp
© 2008 Martin
J. Dürst 青山学院大学
目次
計算量の比較: 具体から抽象へ
- 実行時間の測定
問題: 機種依存、プログラム言語依存など
- ステップの数え上げ
問題: 入力の具体的なデータに依存
- 最悪の場合のステップの数え上げ
問題: データの大きさに依存
- 漸近記号
計算量の本質を抽象化
関数のオーダー
対数の底
O(log2 n) と O(log10
n) はどう違うか
よくあるオーダー
O(n):
データの大きさに比例、全てのデータをチェック
O(log n), O(n log
n):
二分探索など、データを小分けして処理する場合
O(n2),
O(n3):
データの二つ、三つの組み合わせを考える場合
O(2n):
データの全ての部分集合を検討する場合など
多項式の重要性
- 「有用」といわれる計算量は問題によって違う
- 一般的には
- 多項式時間 (polynomial time) は有用
- 指数時間 (exponential time) は現実的でない
抽象データ型
(abstract data type, ADT)
- データとそれを操作する関数のセット
- データは関数を使わないと操作できない
- 膨大なソフトウェアのモジュール化のための概念
- データの完全性のための概念
例: 誕生日と年齢
- 理論で型理論とつながる
- オブジェクト指向によって実装
- 型 → クラス (class)
- 関数 → メソッド (method)
スタック
(stack)
- 具体例
- 食堂の食膳の山
- IT の例
- プログラムの関数呼び出しのためのスタック
- 原理
- last-in-first-out (LIFO)
- 主なメソッド
- 新規作成 (new), 追加 (push), 削除 (pop)
- その他のメソッド
- 空かどうかのチェック、長さ、次のデータ項目をのぞく
(top)
スタックの公理
つぎの六つの公理からスタックの全ての性質を導くことが可能
- Stack.new.empty? ↔ true
- s.push(e).empty? ↔ false
- Stack.new.size ↔ 0
- s.push(e).size ↔ s.size + 1
- s.push(e).top ↔ e
- s.push(e).pop ↔ s // pop
はデータではなく、スタックを返す
s が任意のスタック、e が任意のデータ項目
キュー
(queue)
- 具体例
- 食堂などの待ち行列
- IT の例
- 実行待ちプロセスのキュー
- 原理
- first-in-first-out (FIFO)
ADT の比較
実装: 3ADTs.rb
ADT |
スタック |
キュー |
実装 |
Array |
LinearList |
Array |
LinearList |
新規作成 |
O(n) |
O(1) |
O(n) |
O(1) |
項目追加 |
O(1) |
O(1) |
O(1) |
O(n) |
項目削除 |
O(1) |
O(1) |
O(n) |
O(1) |
empty? |
O(1) |
O(1) |
O(1) |
O(1) |
長さ |
O(1) |
O(n) |
O(1) |
O(n) |
キューの実装
リングバッファ (ring buffer)
双方向連結リスト
線形リスト
(linear list)
辞書
(dictionary)
次回のための準備
- 次の関数をオーダの順にならび、その理由を付けなさい。
O(n2), O(n!),
O(n log log n),
O(n log n),
O(20n),
- Priority Queue という ADT を実装しなさい (Ruby
でも他言語でもよい)
Priority Queue は各要素ごとに優先度 (整数など)
が付く。優先度の高いものが先にキューから出る。実装は配列でも連結リストでもよい。