アルゴリズムとデータ構造 5月27日分 情報知能学科 白井英俊 木構造 根つき木、もしくは木構造 (1) 頂点と辺とから作られる 頂点: vertex, node, ノード、節点、… 辺: edge, arc, アーク、枝、… 木はグラフの一種。 頂点は 、辺は や で表す (2) 根(root) という特別な頂点がただ一つある 木とグラフの違い 木: v0 が根。根からはど の頂点へも枝をたどってい ける。同じ頂点への複数の パスはない。 グラフ: 『根』のような特殊な 頂点はない。v0 からv4へは、 v1を通っても、v2を通ってもい ける(複数のパスがある)。 v0 v1 v3 v2 v4 v5 v7 v1 v6 v8 v0 v2 v3 v4 v5 v6 木の用語 v0 • 親と子 (例: v1とv4) v1 2つの頂点が結ばれていると v2 き、上の頂点を親(parent)、 下の頂点を子(son)、という v4 v5 • 兄弟(例:v4とv5) 同じ親を持つ子頂点同士を 兄 弟(brother)、という v7 v3 v6 v8 •最も左の子を、第一子(first child)という ( 例: v1の第一子は v4、v5の第一子はv7 ) •右隣の兄弟を、次の兄弟(next brother)、という( 例: v1の次 の兄弟はv2、v2の次の兄弟はv3 ) •葉(leaf): 子を持たない頂点(例: v2, v3, v4, v7, …) 木の用語の確認 • 試験の頻出問題 v0 右の木の(1)根, (2)v5の兄弟の頂点 すべて、(3)v6の先祖の頂点すべて、 v1 v2 (4)v2の子孫の頂点すべて、(5)葉の v4 頂点すべて、を答えよ v5 v6 定義:頂点xの「先祖」とは、xの親頂 点すべて、およびxの親頂点の先 v9 祖すべて(再帰的な定義) 定義:頂点xの「子孫」とは、xの子頂 点すべて、およびxの子頂点の子 孫すべて(再帰的な定義) v3 v7 v8 v10 木の表現 • 線形リスト構造を、セル(の集まり)で表したよ うに、木構造を次のようなデータ構造(ノード と呼ぶ)で表す class Node def initialize(u,v,w,x) @label = u @parent = v @firstChild = w @nextBrother = x end end @parent self @nextBrother @firstChild 木の表現(続) クラスNodeを図示すると、次のようになる 頂点 一個一個が以下の構造をもつ @parent 親頂点 label (ラベル) parent (親) self @nextBrother firstChild(第一子) nextBrother(次の兄弟) @firstChild 子頂点 兄弟頂点 前回の練習:木の表現 ラベル v0 v0 nil 親頂点 v1 第一子 nil 次の兄弟 ラベル v1 親頂点 第一子 次の兄弟 ラベル v4 親頂点 第一子 次の兄弟 nil v4 v2 v5 ラベル 親頂点 第一子 次の兄弟 v2 ラベル 親頂点 第一子 次の兄弟 v5 nil nil v3 v6 ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v3 v6 解答:木の表現 ラベル v0 v0 nil 親頂点 v1 第一子 nil 次の兄弟 ラベル v1 親頂点 第一子 次の兄弟 ラベル v4 親頂点 第一子 次の兄弟 nil v4 v2 v5 ラベル 親頂点 第一子 次の兄弟 v2 ラベル 親頂点 第一子 次の兄弟 v5 nil nil v3 v6 ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v3 nil nil v6 nil nil 練習:木の表現 ラベル v0 v0 nil 親頂点 v1 第一子 ラベル v1 親頂点 第一子 次の兄弟 ラベル v4 親頂点 第一子 次の兄弟 v4 nil 次の兄弟 nil nil ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v2 v5 v2 v5 nil v3 v6 ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v3 nil nil v6 nil nil 完成:木の表現 ラベル v0 v0 nil 親頂点 v1 第一子 ラベル v1 親頂点 第一子 次の兄弟 ラベル v4 親頂点 第一子 次の兄弟 v4 nil 次の兄弟 nil nil ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v2 v5 v2 v5 nil v3 v6 ラベル 親頂点 第一子 次の兄弟 ラベル 親頂点 第一子 次の兄弟 v3 nil nil v6 nil nil 木(ノード)のクラスの拡張 その前に前提知識:関数とメソッドの違い ユークリッドの互除法、配列に対するflat, depth、qsort, mergeなどの「関数」 は、たとえば def qsort(x) … end という形式で定義し、 ans = qsort([3,6,9,1,2]) という形式で使ってきた。 この時、仮引数xに実引数の値が渡され、計算が行われる それに対し、クラス定義の「メソッド」の使用の形式は ans = list.insert(2,newCell) のように 「オブジェクト.メソッド(…)」 という形式で使われる。 定義の形式は関数に似ているが、「インスタンス変数」とselfが中で使 える。この時、selfはオブジェクトの値、インスタンス変数はオブジェクト のインスタンス変数の値になる 木(ノード)のクラスの拡張 以下の「ノード」クラスにメソッドを付け加える (1)所与の頂点の祖先を列挙する、(2)所与の頂点の孫を列挙 する、(3) 所与の頂点に別な頂点を第1子として付け加える、 (4)所与の頂点の末っ子の頂点を返す,(5)所与の頂点の第1子 とその子孫を削除する class Node def initialize(u,v,w,x) @label = u @parent = v @firstChild = w @nextBrother = x end end @parent self @nextBrother @firstChild 木のクラスの拡張:children • 準備体操 所与の頂点の子頂点を列挙するメソッド children 考え方: 再帰? 頂点vが持っている情報: 親, 次の兄弟, … すぐ見つかる子頂点は 第1子、つまり @firstChild 他の頂点は? 木のクラスの拡張:children • 準備体操 所与の頂点の子頂点を列挙するメソッド children 考え方: 再帰? 頂点vが持っている情報: 親, 次の兄弟, … すぐ見つかる子頂点は 第1子、つまり @firstChild 他の頂点は? 第1子の兄弟たち これはchildrenとは無関係 だから「children」は(単純な)再帰ではない 木のクラスの拡張:children • それなら「兄弟たち」を返すメソッドを作ってみよう: brothers @parent • これを使えば 子どもたち(children)は、 self 第1子+その兄弟たち @nextBrother でできる(もし第1子があれば) つまり、 @firstChild [@firstChild][email protected] 第1子から見 たnextBrother 木のクラスの拡張:brothers • 兄弟たち:brothers すぐ見つかる兄弟頂点は 次の兄弟、つまり @nextBrother もしも @nextBrother が存在し ない、つまり nil ならば 兄弟たちとして [ ]を返す @parent self @nextBrother @firstChild もしも @nextBrother が存在するなら… 再帰! 兄弟たちとして @nextBrother.brothers を返す brothersとchildren class Node def initialize(u,v,w,x) @label = u @parent = v @firstChild = w @nextBrother = x end def children if @firstChild == nil return [ ] else return [@firstChild] + @firstChild.brothers end # if end # def of children def brothers if @nextBrother == nil return [ ] else return [@nextBrother] + @nextBrother.brothers end # if end # def 補助関数 nodeLabels • 頂点の配列を表示させると、以下のように表示 されて、ワケがわからなくなる [#<Node:0x808e6b8 @firstChild=#<Node:0x808e5f0 @firstChild=nil, @parent=#<Node:0x808e6b8 ...>, @label="d", @nextBrother=#<Node:0x808e5c8 @firstChild=nil, @parent=#<Node:0x808e6b8 ...>, @label="e", @nextBrother=nil>>, ... そこで、頂点の配列を入力とし、頂点のラベルの 配列を返す関数, nodeLabelsを用意した 上記を引数にすると、その結果は: [“x”, “y”] 作業課題 (5)までのヒントが教科書にある 以下のそれぞれをメソッドとして実現せよ (1)所与の頂点の祖先を列挙する ancestors (2)所与の頂点の孫を列挙する grandChildren (3) 所与の頂点に別な頂点を第1子として付け加 える adoptFirstChild (4)所与の頂点の末っ子の頂点を返す theYoungestChild (5)所与の頂点の第1子とその子孫を削除する removeFirstChild (6) 所与の頂点の子孫を列挙する descendants 作業課題をやるときの注意 • いきなりプログラムを書こうとしない! • まずは問題を分析すること 最小の問題は何か?(頂点が与えられた時、すぐ に見つかる答えはどうやって得られるか?) 他の解をどうやって得るか?--再帰が使えるか 、それとも繰り返しか? ancestors の場合 theYoungestChild の場合
© Copyright 2024 ExpyDoc