情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

38
情情情情2 情情情情情情情情情情情情情2

Upload: vidal

Post on 11-Jan-2016

49 views

Category:

Documents


0 download

DESCRIPTION

情報科学( 2 ) 対象のモデル化とデータ構造( 2 ). 連想メモリ ( Associative memory ). 一般的な 離散写像 をデータモデル化したもの 例 数学の点数 山田→ 65 ,鈴木→ 83 ,田中→ 71 ,山本→ 95 , … cf. 配列は連続した整数の 有限部分集合 を 定義域 とする写像 コンピュータのメモリの線形アドレスをうまく利用している 膨大な定義域に散らばるデータとその像の対をコンパクトに表現する 人の名前の集合を 辞書順序 で並べた巨大な表を作れば,辞書を引くように写像を計算することができる - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

情報科学( 2 )

対象のモデル化とデータ構造( 2 )

Page 2: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

連想メモリ( Associative memory )

• 一般的な離散写像をデータモデル化したもの例 数学の点数 山田→ 65 ,鈴木→ 83 ,田中→ 71 ,山本→ 95 ,…

cf. 配列は連続した整数の有限部分集合を定義域とする写像 コンピュータのメモリの線形アドレスをうまく利用している

• 膨大な定義域に散らばるデータとその像の対をコンパクトに表現する人の名前の集合を辞書順序で並べた巨大な表を作れば,辞書を引くように写像を計算することができるしかし, 1 つの教室は高々 50 人なので(定義域が小さいので) ムダ一般的にはハッシュと呼ばれる計算メカニズムを利用して実現配列のアクセスより時間コストが高い

Page 3: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

ハッシュ( Hash )marks = {" 山田 " => 65, " 鈴木 " => 83, " 田中 " => 71, " 山本 " => 95}marks[" 大田 "] = 75marks[" 井上 "] = 48

# このようにどんどん定義域を広げていくことができる

marks[" 鈴木 "] # 鈴木君の点を訊く

# 最初の行と同じことは以下のようにしても可能

marks = Hash.new(0) # 登録されていない学生はとりあえず 0 点にmarks[" 山田 "]=65marks[" 鈴木 "]=83marks[" 田中 "]=71marks[" 山本 "]=95

Ruby

中カッコに注意

Page 4: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

大きさが不定のデータ構造• 配列もレコードもデータを作るときに大きさが決まる

あらかじめ必要な大きさが予想できない場合?途中で大きさが変化する場合?文字列はその典型例

あらかじめ大き目の文字の配列を用意足りなくなったらもっと大きな配列を用意してコピーこのようにシステムが裏方でがんばってくれる場合もある

• 多様なデータ構造についてシステムががんばってくれることは期待できない不定の大きさのデータ構造にユーザが自分で対処する必要あらかじめ大き目の配列を用意するのは一つの手

実際の情報が配列のどこまで入っているかを自分で管理

currentMax arrayBody

k+1

k

レコード 配列未使用部分

k-1 k+1

Page 5: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

中身サイズ可変の配列

# Ruby ではちょっと無理のある例だが…FillArray = Struct.new(:currentMax, :arrayBody)# FillArray と,先頭が大文字になっていることに注意# とりあえずサイズ 100 の配列を用意fillArray = FillArray.new(0, Array.new(100))

# 第 0 要素に "hello" ,第 1 要素に "world" を入れてみるfillArray.arrayBody[fillArray.currentMax] = "hello"fillArray.currentMax += 1   # currentMax を 1 増やす  fillArray.arrayBody[fillArray.currentMax] = "world"fillArray.currentMax += 1

Ruby

Page 6: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

再帰( recursion )• 落語の「頭山」

頭の上にできた水溜りを嘆いて,そこに飛び込んでしまった男の噺 ― 自分で自分に飛び込む ?

• 仕事を下請けに出したら,巡り巡ってその仕事の一部が自分に戻ってきた

• 友達 A のことを紹介しようとして,「 A のいい加減なことといったら,A みたいにいい加減なんだ」と言ってしまった

• 辞典で「白い」を引いたら「雪のような色」と書いてあったが,「雪」を引いたら「空から降ってくる,雨が凍った白く冷たいもの」と書いてあった

• 「秘妙」という造語の意味を説明をしようとして,「『秘妙』という言葉の意味は非常に秘妙であり,説明が難しい」と言ってしまった

しかし,堂々巡りにならないのであれば,再帰は非常に強力な計算の原理

Page 7: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

再帰的定義• 簡単な例階乗の定義  factorial(n) ≡ if n<2 then 1 else n*factorial(n-1)Fibonacci 数の定義  fib(n) ≡ if n<2 then 1 else fib(n-1)+fib(n-2)

• ちゃんとした再帰的定義は堂々巡りにならず,いつかは終端に達するある漢和辞典(明解漢和辞典 1927年)の例

九 八に一を足した數八 七に一を足した數 …二 一に一を足した數一 對なき數.數の始め

Page 8: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

リスト構造( list )• 必要な分だけをつないで使う

例 道順の説明 交差点ごとに直進,右折,左折を示す

"直進 "

"右折 "

"直進 "

"左折 "

どこも指していないことを意味するポインタ  null ま

たは nil"直進 "

"右折 "

"直進 "

"左折 "

"直進 "

いきなり途中の交差点が増えても(減っても)大丈夫構造のほかの場所に影響を与えないで情報更新[ex] 配列で同じことをしたらどうなるか ?

2 つのフィールドをもつセル ポインタは切ったり

張ったりできる

Page 9: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

木構造( tree )• 数式の構造は木構造になじむ

/

+ 1-

3 *

** 2

5 *

)1/()53( 2 +− yxx

数式を扱おうとすると,因数分解や展開でどんどん数式の形が変わる.

このようにあらかじめデータの大きさも形も予測できない場合,ポインタを使って自由に大きさを変えられるとうれしい

x

x

y

Page 10: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

再帰的データ構造

リスト構造 ::= セル | nil | 数や文字列などの基本データ型

セル::= リスト構造とリスト構造の対

木構造 ::= 変数名 | 数 | 木構造と演算子と木構造の 3組

::= は「定義」の意味| (縦棒)は「または」と読む

リスト構造も木構造もいろいろなものがある.ここに示したのはその一例

Page 11: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

再帰的データ構造定義の例# 中置記法の数式に合わせてExpr = Struct.new(:left, :operator, :right)

# 前のスライドの例を無理やり作ってみた

Expr.new( Expr.new( Expr.new(3, :*, Expr.new(:x, :**, 2)), :-, Expr.new(5, :*, :x)), :/, Expr.new(:y, :+, 1))

Ruby

:left と :right に Exprが出てくるので,本来再帰的なデータ構造定義だが, Ruby では陽

にExpr と書かなくてよいので再帰であることが

見えにくい

Page 12: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

基礎的なデータモデル• スタック

ここではオブジェクトとして定義( Ruby のオブジェクト)

• キュー (待ち行列)同じデータモデルの実現にもいろいろなデータ構造がある

• グラフ構造(地下鉄路線図)目的に合ったデータ構造の設計

Page 13: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

スタック( stack )• 後入れ先出し( Last-in First-out )でデータを貯めるもの

原義:干草などを積み重ねたものコンピュータ(特にプログラミング言語の処理系)では重要な概念

しかし,「後入れ先出し」は一般社会では使わないことが推奨される

スーパーの倉庫「先入れ先出しを守れ」(賞味期限がある)

片付かない机の上は先入れ先出しがしにくい構造 例外:トランプの独り遊びには頻出

• 基本操作push データを積むpop データを取り出す,降ろす (降ろさないで見るだけの操作も 通常はある)empty? 空っぽ?と聞く

top

bottom

Page 14: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

スタックの定義class Stack def initialize(size) # new のときの初期化 @data = Array.new(size) @pos = -1 # @pos がスタックのトップを表す.最初はボトムを指す -

1 . end

def push(obj) # obj がプッシュされるデータ @pos += 1 # @pos = @pos + 1 と同じ意味 @data[@pos] = obj # 前頁の図では上のほうが番地が大きい end

def pop @pos -= 1 # 先にトップへのポインタを減らす @data[@pos + 1] # ∵ 最後の式が値となるため end

def empty?() @pos == -1 end

end

Ruby

この定義の後に 試してみよう

s = Stack.new(100) s.push :abc s.push :def p s.pop p s.pop

Page 15: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キュー(待ち行列, queue )• 先入れ先出し( First-in First-out )でデータを貯めるもの要するに先着順( First-Come First-Service )OS ,ネットワーク,シミュレーション,探索などで使われる

• 基本操作enqueue データをキューに並ばせる(末尾につける)dequeue キューの先頭からデータを取るempty? キューが空?

toplast tail

この順に並んでる

Page 16: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造( 1 )

配列top=i last=j

i j

配列top=m last=n

mn

列の最大長さよりも大きい1次元配列を用意し,それを循環的に使うtop と last のほかにキューの長さを表す変数を使うこともある

変数 tail が,次にデータが入るところの添え字を表す方法もある(こちらのほうが普通)

• 1次元配列とそれの添え字を値としてとる 2個の変数で表すまず,複雑なデータ構造の定義がしにくい言語での方法

Page 17: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j

i j

配列top=m last=n

mn

enqueue

Page 18: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j+1

i j+1

配列top=m last=n

mn

enqueue

Page 19: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j+1

i j+1

配列top=m last=n

mn

enqueue

Page 20: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j+1

i j+1

配列top=m last=n+1

mn+1

enqueue

Page 21: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j

i j

配列top=m last=n

mn

dequeue

Page 22: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i+1 last=j

i+1 j

top=m last=n

mn

dequeue

配列

Page 23: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

配列top=i last=j

i+1 j

top=m+1 last=n

m+1n

dequeue

配列

Page 24: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造( 2 )

j

レコード(簡略に書いた)

arrayi

• 変数と配列を一体化したレコードにする方法ここでは,キューの最後を次に並ぶ場所の添え字にするさらにキューに並んでいるデータの個数もレコードに入れる

top tail length

i j n

n

Page 25: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

ji

top tail length

i j n

n

enqueue

array

Page 26: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

j+1i

top tail length

i j n+1

n+1

enqueue

array

Page 27: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

ji

top tail length

i j n

n

dequeue

array

Page 28: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

ji+1

top tail length

i j n-1

n-1

dequeue

array

Page 29: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造(3)• レコードの中で配列の代わりにリスト構造キューの最大長さが予測できないときに便利リスト構造は先頭はともかく,末尾にアクセスするのに時間がかかるしかし,工夫すると,先頭も末尾もほぼ同じ速度でアクセス可能以下はその一例(ほかにいっぱいデータモデル化の方法がある)

top last

キューへのポインタ

循環リストになっている

Page 30: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造(3)続き

top last

キューへのポインタ enqueue

どちらの操作もキューの長さに依存しない一定時間で処理することが可能(キューが空から出発する,あるいは空になるときは処理に要注意)

top last

キューへのポインタ dequeue

Page 31: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造(3)続き

top last

キューへのポインタ

new

enqueue

どちらの操作もキューの長さに依存しない一定時間で処理することが可能(キューが空から出発する,あるいは空になるときは処理に要注意)

last

キューへのポインタ dequeue

top

Page 32: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューの3通りのデータ構造(3)続き

top last

キューへのポインタ

new

enqueue

どちらの操作もキューの長さに依存しない一定時間で処理することが可能(キューが空から出発する,あるいは空になるときは処理に要注意)

top last

キューへのポインタ dequeue

Page 33: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューのデータ構造( 2 )

MyQueue = Struct.new(:top, :tail, :length, :array)

def enqueue(q, data) q.array[q.tail] = data q.tail = (q.tail + 1) % q.array.size # % は余りを求める演算 (循環するた

め) q.length += 1end

def dequeue(q) value = q.array[q.top] q.top = (q.top + 1) % q.array.size q.length-= 1 valueend

def empty?(q) q.length == 0end

Ruby

試してみようq = MyQueue.new(0, 0, 0, Array.new(100))

p empty?(q)enqueue(q, :x)p empty?(q)enqueue(q, :y)enqueue(q, :z)p dequeue(q)p dequeue(q)p dequeue(q)p empty?(q)

Page 34: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

キューのデータ構造( 3 )

Cell = Struct.new(:value, :next)$ptr = nil

def enqueue(data) if $ptr != nil cell = Cell.new(data, $ptr.next) $ptr.next = cell $ptr = cell else $ptr = Cell.new(data, nil) $ptr.next = $ptr endend

Ruby

def dequeue cell = $ptr.next

if $ptr.next != $ptr $ptr.next = cell.next else $ptr = nil end cell.valueend

def empty? $ptr == nilend

一言リマーク: Rubyでは.オブジェクトにしないのが不自然

$ は大域変数の意味

Page 35: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

地下鉄路線図http://www.tokyometro.jp/rosen/rosenzu/index.html

Page 36: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

地下鉄路線図のデータモデル• データモデルにして何をしたいかをまず考える発駅から着駅までの最短の経路を探索する発駅から着駅までの最も安い経路を探索する発駅から着駅までの乗り換え回数最小の経路を探索する乗り換え所要時間も考慮に入れる?発駅から5駅以内で行けるすべての駅を数え上げる駅名が漢字5文字以上の駅を列挙するJR との乗換駅を列挙する…

• どの操作が最も頻繁に使われるか,重要かを考えるそれらに適したデータモデル化(一つとは限らない)アルゴリズムやプログラミングに関する土地勘が必要次回以降の講義でそれらの素養を学ぶ

Page 37: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

地下鉄路線図のデータモデルの一例 (1)

line name up upD down downD exchangeList

"東西線 " "茅場町駅 " 0.5 0.8

駅のデータの集合として地下鉄路線図を表す例えば東西線茅場町駅を表すデータ( Station )大文字の D は距離( Distance )の意味

東西線日本橋駅のデータ

東西線門前仲町駅のデータ

日比谷線茅場町駅のデータ

station timeForExchange nextExchange

3プログラミング言語で書くのは演習

Page 38: 情報科学( 2 ) 対象のモデル化とデータ構造( 2 )

地下鉄路線図のデータモデルの一例 (2)

人が見る時刻表のように路線ごとにまとめて表にしてしまうのでもよいこのとき路線名や駅名から連想メモリを使うのではなく,それらに通し番号をつけると配列だけでかなりのことができる

銀座線

丸の内線

東西線

有楽町線

南北線

大江戸線

中野 0

落合 2.0

高田馬場 1.9

早稲田 1.7

神楽坂 1.2

飯田橋 1.2

3 13 4

路線番号 駅番号 所要時間

乗換え距離

次候補