1 / 38

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

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

vidal
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. 連想メモリ(Associative memory) • 一般的な離散写像をデータモデル化したもの • 例 数学の点数 山田→65,鈴木→83,田中→71,山本→95,… • cf. 配列は連続した整数の有限部分集合を定義域とする写像 • コンピュータのメモリの線形アドレスをうまく利用している • 膨大な定義域に散らばるデータとその像の対をコンパクトに表現する • 人の名前の集合を辞書順序で並べた巨大な表を作れば,辞書を引くように写像を計算することができる • しかし,1つの教室は高々50人なので(定義域が小さいので) ムダ • 一般的にはハッシュと呼ばれる計算メカニズムを利用して実現 • 配列のアクセスより時間コストが高い

  3. Ruby ハッシュ(Hash) marks = {"山田" => 65, "鈴木" => 83, "田中" => 71, "山本" => 95} marks["大田"] = 75 marks["井上"] = 48 # このようにどんどん定義域を広げていくことができる marks["鈴木"] # 鈴木君の点を訊く # 最初の行と同じことは以下のようにしても可能 marks = Hash.new(0) # 登録されていない学生はとりあえず0点に marks["山田"]=65 marks["鈴木"]=83 marks["田中"]=71 marks["山本"]=95 中カッコに注意

  4. 大きさが不定のデータ構造 • 配列もレコードもデータを作るときに大きさが決まる • あらかじめ必要な大きさが予想できない場合? • 途中で大きさが変化する場合? • 文字列はその典型例 • あらかじめ大き目の文字の配列を用意 • 足りなくなったらもっと大きな配列を用意してコピー • このようにシステムが裏方でがんばってくれる場合もある • 多様なデータ構造についてシステムががんばってくれることは期待できない • 不定の大きさのデータ構造にユーザが自分で対処する必要 • あらかじめ大き目の配列を用意するのは一つの手 • 実際の情報が配列のどこまで入っているかを自分で管理 k-1 k k+1 レコード 配列 未使用部分

  5. Ruby 中身サイズ可変の配列 # 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

  6. 再帰(recursion) • 落語の「頭山」 • 頭の上にできた水溜りを嘆いて,そこに飛び込んでしまった男の噺 ― 自分で自分に飛び込む? • 仕事を下請けに出したら,巡り巡ってその仕事の一部が自分に戻ってきた • 友達Aのことを紹介しようとして,「Aのいい加減なことといったら,Aみたいにいい加減なんだ」と言ってしまった • 辞典で「白い」を引いたら「雪のような色」と書いてあったが,「雪」を引いたら「空から降ってくる,雨が凍った白く冷たいもの」と書いてあった • 「秘妙」という造語の意味を説明をしようとして,「『秘妙』という言葉の意味は非常に秘妙であり,説明が難しい」と言ってしまった しかし,堂々巡りにならないのであれば, 再帰は非常に強力な計算の原理

  7. 再帰的定義 • 簡単な例 • 階乗の定義 • 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年)の例 • 九 八に一を足した數 • 八 七に一を足した數 • … • 二 一に一を足した數 • 一 對なき數.數の始め

  8. リスト構造(list) • 必要な分だけをつないで使う • 例 道順の説明 交差点ごとに直進,右折,左折を示す 2つのフィールドをもつセル どこも指していないことを意味するポインタ null または nil ポインタは切ったり張ったりできる いきなり途中の交差点が増えても(減っても)大丈夫 構造のほかの場所に影響を与えないで情報更新 [ex] 配列で同じことをしたらどうなるか?

  9. 木構造(tree) • 数式の構造は木構造になじむ 数式を扱おうとすると,因数分解や展開でどんどん数式の形が変わる. このようにあらかじめデータの大きさも形も予測できない場合,ポインタを使って自由に大きさを変えられるとうれしい

  10. 再帰的データ構造 ::= は「定義」の意味 | (縦棒)は「または」と読む リスト構造 • ::= セル | nil | 数や文字列などの基本データ型 セル • ::= リスト構造とリスト構造の対 木構造 • ::= 変数名 | 数 | 木構造と演算子と木構造の3組 リスト構造も木構造もいろいろなものがある. ここに示したのはその一例

  11. Ruby 再帰的データ構造定義の例 # 中置記法の数式に合わせて 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)) :leftと:rightにExpr が出てくるので,本来 再帰的なデータ構造定義だが,Rubyでは陽に Exprと書かなくてよい ので再帰であることが 見えにくい

  12. 基礎的なデータモデル • スタック • ここではオブジェクトとして定義(Rubyのオブジェクト) • キュー (待ち行列) • 同じデータモデルの実現にもいろいろなデータ構造がある • グラフ構造(地下鉄路線図) • 目的に合ったデータ構造の設計

  13. スタック(stack) • 後入れ先出し(Last-in First-out)でデータを貯めるもの • 原義:干草などを積み重ねたもの • コンピュータ(特にプログラミング言語の処理系)では重要な概念 • しかし,「後入れ先出し」は一般社会では使わないことが推奨される • スーパーの倉庫「先入れ先出しを守れ」(賞味期限がある) • 片付かない机の上は先入れ先出しがしにくい構造 • 例外:トランプの独り遊びには頻出 • 基本操作 • pushデータを積む • popデータを取り出す,降ろす • (降ろさないで見るだけの操作も • 通常はある) • empty?空っぽ?と聞く top bottom

  14. Ruby スタックの定義 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 この定義の後に 試してみよう s = Stack.new(100) s.push :abc s.push :def p s.pop p s.pop

  15. キュー(待ち行列,queue) • 先入れ先出し(First-in First-out)でデータを貯めるもの • 要するに先着順(First-Come First-Service) • OS,ネットワーク,シミュレーション,探索などで使われる • 基本操作 • enqueueデータをキューに並ばせる(末尾につける) • dequeueキューの先頭からデータを取る • empty?キューが空? last tail top この順に並んでる

  16. キューの3通りのデータ構造(1) • 1次元配列とそれの添え字を値としてとる2個の変数で表す • まず,複雑なデータ構造の定義がしにくい言語での方法 列の最大長さよりも大きい 1次元配列を用意し,それを 循環的に使う topとlastのほかにキューの 長さを表す変数を使うことも ある 変数tailが,次にデータが 入るところの添え字を表す 方法もある(こちらのほうが 普通) top=i last=j 配列 j i last=n top=m 配列 n m

  17. enqueue top=i last=j 配列 j i last=n top=m 配列 n m

  18. enqueue top=i last=j+1 配列 i j+1 last=n top=m 配列 n m

  19. enqueue top=i last=j+1 配列 i j+1 last=n top=m 配列 n m

  20. enqueue top=i last=j+1 配列 i j+1 last=n+1 top=m 配列 n+1 m

  21. dequeue top=i last=j 配列 j i last=n top=m 配列 n m

  22. dequeue top=i+1 last=j 配列 j i+1 last=n top=m 配列 n m

  23. dequeue top=i last=j 配列 j i+1 last=n top=m+1 配列 n m+1

  24. キューの3通りのデータ構造(2) • 変数と配列を一体化したレコードにする方法 • ここでは,キューの最後を次に並ぶ場所の添え字にする • さらにキューに並んでいるデータの個数もレコードに入れる array i j レコード(簡略に書いた) n

  25. enqueue array i j n

  26. enqueue array i j+1 n+1

  27. dequeue array i j n

  28. dequeue array j i+1 n-1

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

  30. キューの3通りのデータ構造(3)続き enqueue キューへのポインタ top last キューへのポインタ dequeue top last どちらの操作もキューの長さに依存しない一定時間で処理することが可能 (キューが空から出発する,あるいは空になるときは処理に要注意)

  31. キューの3通りのデータ構造(3)続き enqueue キューへのポインタ top last キューへのポインタ dequeue top last どちらの操作もキューの長さに依存しない一定時間で処理することが可能 (キューが空から出発する,あるいは空になるときは処理に要注意)

  32. キューの3通りのデータ構造(3)続き enqueue キューへのポインタ top last キューへのポインタ dequeue top last どちらの操作もキューの長さに依存しない一定時間で処理することが可能 (キューが空から出発する,あるいは空になるときは処理に要注意)

  33. Ruby キューのデータ構造(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 += 1 end def dequeue(q) value = q.array[q.top] q.top = (q.top + 1) % q.array.size q.length-= 1 value end def empty?(q) q.length == 0 end 試してみよう 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)

  34. Ruby キューのデータ構造(3) def dequeue cell = $ptr.next if $ptr.next != $ptr $ptr.next = cell.next else $ptr = nil end cell.value end def empty? $ptr == nil end 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 end end $は大域変数の意味 一言リマーク:Rubyでは.オブジェクトにしないのが不自然

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

  36. 地下鉄路線図のデータモデル • データモデルにして何をしたいかをまず考える • 発駅から着駅までの最短の経路を探索する • 発駅から着駅までの最も安い経路を探索する • 発駅から着駅までの乗り換え回数最小の経路を探索する • 乗り換え所要時間も考慮に入れる? • 発駅から5駅以内で行けるすべての駅を数え上げる • 駅名が漢字5文字以上の駅を列挙する • JRとの乗換駅を列挙する • … • どの操作が最も頻繁に使われるか,重要かを考える • それらに適したデータモデル化(一つとは限らない) • アルゴリズムやプログラミングに関する土地勘が必要 • 次回以降の講義でそれらの素養を学ぶ

  37. 地下鉄路線図のデータモデルの一例(1) 駅のデータの集合として地下鉄路線図を表す 例えば東西線茅場町駅を表すデータ(Station) 大文字のDは距離(Distance)の意味 東西線日本橋駅のデータ 東西線門前仲町駅のデータ プログラミング言語 で書くのは演習 日比谷線茅場町駅のデータ

  38. 地下鉄路線図のデータモデルの一例(2) 人が見る時刻表のように路線ごとにまとめて表にしてしまうのでもよい このとき路線名や駅名から連想メモリを使うのではなく,それらに通し番号を つけると配列だけでかなりのことができる 距離 乗換え 所要時間 次候補 路線番号 駅番号

More Related