データ構造とアルゴリズム

第四回 (2014年10月10日)

抽象データ型とデータ構造、スタック、キューなど

http://www.sw.it.aoyama.ac.jp/2014/DA/lecture4.html

Martin J. Dürst

AGU

© 2009-14 Martin J. Dürst 青山学院大学

目次

前回の残りとまとめ

関数の漸近的増加は次の記法で表現可能:

  f(n)∈O(g(n)) の条件は ∃c>0: ∃n0≥0: ∀nn0: f(n)≤c·g(n) で、
確認は cn0 の選択や極限の利用で可能

O() 記法では常に一番簡単な書き方を選択

 

多項式増加と指数的増加の比較

実例:

1.1nn20

log(1.1)·n ≶ log(n)·20

n/log10(n) ≶ 20/log10(1.1) ≊483.2

n0 ≊ 1541

a, b > 1 の場合、an の漸近的な増加は nb の漸近的な増加より必ず大きい

対数の底

O(log2 n) と O(log10 n) はどう違うか

logb a = logc a / logc b = logc a · logb c

log10 n = log2 n · log10 2 ≅ 0.301 · log2 n

O(log10 n) = O(0.301 · log2 n) = O(log2 n)

一般の定数 ab (a>1, b>1) の場合、O(loga n) = O(logb n) = O(log n)

前回の宿題

(提出不要)

ウェブなどで O(1), O(log n), O(n), O(n log n), O(n2), O(n3), O(2n), O(n!) のアルゴリズムを探す

よくあるオーダー

O(log n) (logarithmic order/time), O(n log n): 二分探索など、データを小分けして処理する場合

O(n) (linear order, linear time): データの大きさに比例、全てのデータをチェック

O(n2) (quadratic order/time), O(n3) (cubic order/time): 二つ、三つのデータの組み合わせを考える場合

O(2n): データの全ての部分集合を検討する場合など

O(n!): データの全ての順序を検討するなど

多項式の重要性

アルゴリズムの漸近的計算量の求め方

入力の大きさの変数の決定

一番多く実行される操作の特定

操作の数の算出 (総和)

 

操作の数の算出 (漸化式)

 

漸化式

(recurrence 又は recurrence relation)

 

アルゴリズムの計算量の比較

例: 線形探索と2分探索の比較

結論: 計算量を O() 記法で表すことで、アルゴリズムそのものの根本的な速さの比較が可能

抽象データ型

(abstract data type, ADT)

 

抽象データ型の典型例

スタック

(stack)

原理
last-in-first-out (LIFO)
具体例
食堂の食膳の山
IT の例
プログラムの関数呼び出し用のスタック
主なメソッド
新規作成 (new), 追加 (push), 削除 (pop)
その他のメソッド
空かどうかのチェック (empty?)、最上のデータ項目をのぞく (top)

 

スタックの公理

つぎの四つの公理でスタックの定義が可能

  1. Stack.new.empty? ↔ true
  2. s.push(e).empty? ↔ false
  3. s.push(e).top ↔ e
  4. s.push(e).pop ↔ s (pop はデータではなく、スタックを返す場合)

(s が任意のスタック、e が任意のデータ項目)

公理は実装側と使用側の間の約束事

キュー

(queue、待ち行列)

原理
first-in-first-out (FIFO)
具体例
食堂などの待ち行列
IT の例
実行待ちプロセスのキュー
主なメソッド: 追加 (enqueue), 削除 (dequeue)
Explain the meaning of GIGO: Garbage in, garbage out.

ADT の比較

実装: 4ADTs.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(1) O(n)* 又は O(1) O(1)
empty? O(1) O(1) O(1) O(1)
長さ O(1) O(n) O(1) O(n)

*) リングバッファ (ring buffer) により O(1) に改善可能

まとめ

次回のための準備

  1. 次の関数をオーダの順にならび、その理由を付けなさい。

    O(n2), O(n!), O(n log log n), O(n log n), O(20n),

  2. 4ADTs.rb にあるクラスを使う簡単なプログラムを作成し、実装の性能を比較しなさい。
  3. 順位キュー (priority queue) という ADT を実装しなさい (Ruby でも他言語でもよい)

    順位キューは各要素ごとに優先度 (整数など) が付く。一番簡単な場合にデータ項目は優先度だけ。優先度の高いものが先にキューから出る。実装は配列でも連結リストでもその他のデータ構造でもよいよい。