• 検索結果がありません。

ALG2012-A.ppt

N/A
N/A
Protected

Academic year: 2021

シェア "ALG2012-A.ppt"

Copied!
18
0
0

読み込み中.... (全文を見る)

全文

(1)

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

2012年7月9日

酒居敬一

(

[email protected]

)

(2)

グラフの定義(225ページ)

•  グラフは頂点の集合と辺の集合からなる。

•  グラフには有向グラフと無向グラフがある。

•  グラフに対する、教科書4章の仮定。

–  (v, v)の形の辺(NDAのε遷移みたいなの)はない。

–  頂点uからvへ結ぶ辺は高々1つ。

•  辺の属性として数値を持つ場合、重みという。

•  いくつかの辺をつないでできる経路は道。

–  有向グラフでは辺はすべて同じ向きをたどる。

•  頂点からその頂点自身への道は閉路。

•  木はグラフの一種。

(3)

グラフの定義(つづき)

•  木が複数集まったグラフは森という。

–  木と木がつながっていなくてもいい。

•  頂点につながる辺の数を次数という。

–  有向グラフでは、入次数・出次数と区別する。

•  正則グラフでは全頂点の次数が同じ。

–  このときの次数をグラフの次数とする場合がある。

•  ハイパーキューブなど

•  グラフ全体を組織的に調べることを探索という。

–  ただし、単に頂点を訪問するだけ、かもしれない。

(4)

グラフアルゴリズムの計算量

•  頂点数をnとしたときの最大の辺の数mは、

無向グラフでは

有向グラフでは

•  辺の数が最大のものを完全グラフという。

•  辺の数が0でもグラフである。

•  密なグラフか、疎なグラフか。

–  次数がある程度以下なら疎と考える。

•  「ある程度」とは、問題に依存する。

•  CCC(Cude Connected Cycle)なら次数は3。疎?

•  人工的なネットワークか、自然なネットワークか。

2

/

)

1

(

2

=

×

=

C

n

n

m

n

)

1

(

×

=

n

n

m

(5)

グラフの表現法(230ページ)

•  隣接行列

–  頂点から頂点への接続の有無や辺の重みを持つ

–  密なグラフにはいい

•  配列やListやSetやMapによる表現

–  正則グラフなら配列

–  二分探索木のような順序木のグラフならList

–  無向グラフならListでもSetでもMapでもいい

•  MapならKeyを接続先の頂点、Valueを重みにするなど

•  計算で求める

–  配列上のヒープソートの、部分順序つき二分木

–  スパコン内部ネットワークなど

(6)

0000

0110

1101

1110

1111

1011

0111

0101

0011

0100

0010

0001

1100

1010

1001

1000

(7)

図4

.3.2 a

図4

.3.2 b

図4

.3.3

深さ優先探索

(234ページ)

• 木の辺(実線で表示)

• 逆辺(点線で表示)

• 連結グラフなら木が得られ、

 そうでなければ森が得られる

(8)

8

public class Node<E> {

private E value; // 頂点の値

private Collection<Node<E>> edges; // 有向辺 private boolean visited;

private int sequence;

private boolean searching;

public Node(E value, Collection<Node<E>> edges) { this.value = value;

this.edges = edges; reset();

}

public void reset(){ this.visited = false; this.sequence = 0; this.edges.clear(); this.searching = false; } public E getValue() { // 頂点の値を得る。 return value; }

public Collection<Node<E>> getEdges(){ return this.edges;

}

グラフの頂点を表すクラス

4.3と4.4で使う)

public boolean isVisited() { return visited;

}

public void setVisited(boolean v) { this.visited = v;

}

public int getSequence() { return sequence;

}

public void setSequence(int s) { this.sequence = s;

}

public boolean isSearching() { return searching;

}

public void setSearching(boolean s) { this.searching = s;

}

public void connect(Node<E> to){

this.edges.add(to); //無向辺を追加 if( !to.getEdges().contains(this) ){ to.getEdges().add(this);

} }

public void connectTo(Node<E> to){ this.edges.add(to); //有向辺を追加 }

(9)

9 private static Node<Character> nodeA = new Node<Character>('A', new LinkedList<Node<Character>>()); private static Node<Character> nodeB = new Node<Character>('B', new LinkedList<Node<Character>>()); private static Node<Character> nodeC = new Node<Character>('C', new LinkedList<Node<Character>>()); private static Node<Character> nodeD = new Node<Character>('D', new LinkedList<Node<Character>>()); private static Node<Character> nodeE = new Node<Character>('E', new LinkedList<Node<Character>>()); private static Node<Character> nodeF = new Node<Character>('F', new LinkedList<Node<Character>>()); private static Node<Character> nodeG = new Node<Character>('G', new LinkedList<Node<Character>>()); private static Collection<Node<Character>> test_data = new LinkedList<Node<Character>>();

static { test_data.add(nodeA); test_data.add(nodeB); test_data.add(nodeC); test_data.add(nodeD); test_data.add(nodeE); test_data.add(nodeF); test_data.add(nodeG); }

public class DepthFirstSearch {

private static <E> void visit(Node<E> node){ node.setVisited(true);

System.out.print(node.getValue());

for(Node<E> neighbor: node.getEdges()){

if(neighbor.isVisited()) continue; // 訪問済み System.out.print(" -> ");

visit(neighbor); }

}

public static <E> void search(Collection<Node<E>> graph){ for(Node<E> node: graph){

if(node.isVisited()) continue; // 訪問済み System.out.println(node.getValue() + "から探索します。"); visit(node); System.out.println(); } } }

深さ優先探索のプログラム

テストデータのうち、

グラフの頂点とその集合

(10)

10

public static void main(String[] args) { System.out.println("図4.3.2");

for(Node<Character> node: test_data){ node.reset(); } nodeA.connect(nodeC); nodeA.connect(nodeD); nodeA.connect(nodeB); nodeC.connect(nodeE); nodeC.connect(nodeF); nodeD.connect(nodeB); nodeD.connect(nodeF); nodeE.connect(nodeG); nodeE.connect(nodeF); search(test_data); }

public static void main(String[] args) { System.out.println("図4.3.3");

for(Node<Character> node: test_data){ node.reset(); } nodeA.connect(nodeC); nodeA.connect(nodeD); nodeA.connect(nodeB); nodeC.connect(nodeF); nodeC.connect(nodeE); nodeD.connect(nodeB); nodeD.connect(nodeF); nodeE.connect(nodeG); nodeE.connect(nodeF); search(test_data); }

public static void main(String[] args) { System.out.println("図4.3.4");

for(Node<Character> node: test_data){ node.reset(); } nodeA.connectTo(nodeC); nodeA.connectTo(nodeD); nodeA.connectTo(nodeE); nodeC.connectTo(nodeB); nodeB.connectTo(nodeA); nodeD.connectTo(nodeC); nodeD.connectTo(nodeE); nodeF.connectTo(nodeA); nodeF.connectTo(nodeG); search(test_data); }

図4.3.3

Aから探索します。

A -> C -> F -> D -> B -> E -> G

図4.3.2

Aから探索します。

A -> C -> E -> G -> F -> D -> B

図4.3.4

Aから探索します。

A -> C -> B -> D -> E

Fから探索します。

F -> G

(11)

図4

.3.4 a

図4

.3.4 b

連結グラフとは、グラフ全体が

つながっていること。無向グラフ

では、深さ優先探索で全ての

頂点をたどる事ができれば連結

グラフである。

しかし、有向グラフでは必ずしも

そうとはならない。

上昇辺

交差辺

交差辺

下降辺

• 上昇辺

 子孫から祖先へ向かう辺

 無向グラフでは逆辺

• 下降辺

 祖先から子孫へ向かう辺

 無向グラフでは逆辺

• 交差辺

 上昇辺でも下降辺でもない辺

(12)

public class DirectedDepthFirstSearch<E> { private int sequence;

private void visit(Node<E> node){ node.setVisited(true);

node.setSequence(++this.sequence); node.setSearching(true);

System.out.print(node.getValue());

for(Node<E> neighbor: node.getEdges()){ if(neighbor.getSequence() == 0){

System.out.print(" -> "); visit(neighbor); // 木の辺

} else if (neighbor.getSequence() > node.getSequence()) {

System.out.print(" 下降辺(" + node.getValue() + ", " + neighbor.getValue() + ")"); } else if (neighbor.isSearching()){

System.out.print(" 上昇辺(" + node.getValue() + ", " + neighbor.getValue() + ")"); } else {

System.out.print(" 交差辺(" + node.getValue() + ", " + neighbor.getValue() + ")"); }}

node.setSearching(false); }

public void search(Collection<Node<E>> graph){ this.sequence = 0;

for(Node<E> node: graph){

if(node.getSequence() == 0){ System.out.println(node.getValue() + "から探索します。"); visit(node); System.out.println(); }}}} 12

有向グラフの深さ優先探索

(240ページ)

(13)

public static void main(String[] args) { System.out.println("図4.3.4");

for(Node<Character> node: test_data){ node.reset(); } nodeA.connectTo(nodeC); nodeA.connectTo(nodeD); nodeA.connectTo(nodeE); nodeC.connectTo(nodeB); nodeB.connectTo(nodeA); nodeD.connectTo(nodeC); nodeD.connectTo(nodeE); nodeF.connectTo(nodeA); nodeF.connectTo(nodeG); new DirectedDepthFirstSearch<Character>().search(test_data); } 13

図4.3.4

Aから探索します。

A -> C -> B 上昇辺(B, A) -> D 交差辺(D, C) -> E 下降辺(A, E)

Fから探索します。

(14)

トポロジカルソート

(242ページ)

4.3.6 DAG

(Directed Acyclic Graph)

• Topology は「位相」のこと。トポロジカルソートのときはこちら。

• Phase も「位相」と訳せます。ベクタの位相はこちら。

⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 0 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 2 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 2 0 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 5 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 4 3 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 5 0 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 0 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 2 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 2 0 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 0 5 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 4 3 ⎥ ⎦ ⎤ ⎢ ⎣ ⎡ 5 0

たとえば、ベクターがあったとします。

大きさ0

大きさ2

大きさ

5

大きさを比較することは

できますが、大きさが同じ

だからといって同じベクター

であるとは限りませんよね?

   全要素間で順序がつけられる → 全順序関係

一部の要素間に順序がつけられる → 半順序関係

同じだけど同じじゃない、というのは順序がつけられて

ません。そういうデータは、DAGで保持することができる。

(15)

図4

.3.2 a

図4

.3.7

幅優先探索

(244ページ)

(16)

public class BreadthFirstSearch {

public static <E> void search(Collection<Node<E>> graph){

Queue<Node<E>> queue = new LinkedList<Node<E>>(); // FIFO for(Node<E> node: graph){

if(node.isVisited()){ continue; // 訪問済み } queue.add(node); // enqueue node.setVisited(true); while( !queue.isEmpty() ){

Node<E> next = queue.remove(); // dequeue System.out.print("頂点" + next.getValue());

for(Node<E> neighbor: next.getEdges()){ if( neighbor.isVisited() ){

continue; }

queue.add(neighbor); // enqueue neighbor.setVisited(true);

System.out.print(" 辺(" + next.getValue() + ", " + neighbor.getValue() + ")"); } System.out.print(" -> "); } System.out.println(); } } } 16

(17)

public static void main(String[] args) { System.out.println("図4.3.7");

for(Node<Character> node: test_data){ node.reset(); } nodeA.connect(nodeC); nodeA.connect(nodeD); nodeA.connect(nodeB); nodeC.connect(nodeE); nodeC.connect(nodeF); nodeD.connect(nodeB); nodeD.connect(nodeF); nodeE.connect(nodeG); nodeE.connect(nodeF); search(test_data); } 17

図4.3.7

頂点A 辺(A, C) 辺(A, D) 辺(A, B) ->

頂点C 辺(C, E) 辺(C, F) ->

頂点D ->

頂点B ->

頂点E 辺(E, G) ->

頂点F ->

頂点G ->

(18)

public class DepthFirstSearchStack {

public static <E> void search(Collection<Node<E>> graph){

Stack<Node<E>> stack = new Stack<Node<E>>(); // LIFO for(Node<E> node: graph){

if(node.isVisited()){ continue; // 訪問済み } stack.push(node); // push node.setVisited(true); while( !stack.empty() ){

Node<E> next = stack.pop(); // pop System.out.print("頂点" + next.getValue());

for(Node<E> neighbor: next.getEdges()){ if( neighbor.isVisited() ){ continue; } stack.add(neighbor); // push neighbor.setVisited(true); } System.out.print(" -> "); } System.out.println(); } } } 18

BreadthFirstSearchのFIFO(リスト)を

LIFO(スタック)に変えたもの。

この変更により、幅優先探索だったプログラムが

深さ優先探索プログラムになる。

(247ページ)

参照

関連したドキュメント

現実感のもてる問題場面からスタートし,問題 場面を自らの考えや表現を用いて表し,教師の

*海外派遣にかかる渡航や現地滞在にかかる手配は UNV を通じて行います (現地生活費の支給等を含む)

テキストマイニング は,大量の構 造化されていないテキスト情報を様々な観点から

A., Miller, J., 1981 : Dynamically consistent nonlinear dynamos driven by convection in a rotating spherical shell.. the structure of the convection and the magnetic field without

では、シェイク奏法(手首を細やかに動かす)を音

・条例手続に係る相談は、御用意いただいた書類 等に基づき、事業予定地の現況や計画内容等を

D