1 / 20

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

アルゴリズムとデータ構造. 2012 年 6 月 14 日 酒居敬一 ( sakai.keiichi@kochi-tech.ac.jp ) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/ALG/2012/index.html. ルートノード. エッジ. ノード. 末端ノード. 木構造. ルートとそれ以外の ノードにちょうど1つだけ の経路しか存在しない. 201 2 年6月14日. データ. データ. データ. データ. データ. データ. データ. 左. 左. 左. 左. 左. 左.

alissa
Download Presentation

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

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. アルゴリズムとデータ構造 2012年6月14日 酒居敬一(sakai.keiichi@kochi-tech.ac.jp) http://www.info.kochi-tech.ac.jp/k1sakai/Lecture/ALG/2012/index.html

  2. ルートノード エッジ ノード 末端ノード 木構造 ルートとそれ以外の ノードにちょうど1つだけ の経路しか存在しない

  3. 2012年6月14日 データ データ データ データ データ データ データ 左 左 左 左 左 左 左 右 右 右 右 右 右 右 二分木 • 各ノードが持てる子の数が高々2である木 • 二分探索木として、順序木を使う

  4. 二分探索木 • 二分木を次のルールで作成 • 親よりも小さい値を持つ子は左 • 親よりも大きい値を持つ子は右 29 20 32 30 14 24 48 7 19 21 31

  5. 29 20 32 14 24 30 48 7 19 21 31 ノードの探索 ノード数をNとすると O(log N) の計算量で探索できる 木が偏っているときは 最悪O(N)になるが…

  6. 最悪の形(二分探索木) 48 32 31 ノード数をNとすると O(log N) の計算量で探索できる 木が偏っているときは 最悪O(N)になるが… 30 29 24 21 20 木の深さをバランスよく したものを平衡木という 平衡木については次回述べる 19 14 7

  7. public class MyData implements Comparable { public MyData(int anId, Object aData) { this.id = anId; this.data = aData; } public int compareTo(Object aTarget) { int targetId = ((MyData)aTarget).getId(); if(this.id == targetId){ return 0; } if(this.id > targetId){ return 1; } return -1; } public Object getData() { return this.data; } public int getId() { return (this.id); } public String toString() { return "(" + this.id + "'" + this.data + ")"; } private Object data; // 木に保持したいデータ private int id; // 順序付けのための数値 } 二分探索木のノードに置くデータを表すクラス interface Comparableには、compareTo()というメソッドが存在する。 public int compareTo(Object o); thisオブジェクトを指定されたオブジェクトと比較し、  小さい場合は負の整数、  等しい場合はゼロ、  大きい場合は正の整数、 をそれぞれ返す。

  8. 二分探索木のノードを表すクラス ノードに関する操作 public class MyNode { public MyNode(MyData aData) { this.data = aData; } public MyData getData() { return this.data; } public MyNode getLeft() { return this.left; } public MyNode getRight() { return this.right; } public void setLeft(MyNode aNode) { this.left = aNode; } public void setRight(MyNode aNode) { this.right = aNode; } public String toString() { MyData leftdata = null; MyData rightdata = null; if(null != this.left){ leftdata = this.left.getData(); } if(null != this.right){ rightdata = this.right.getData(); } return ("{"+leftdata+","+this.data+","+rightdata+"}"); } private MyData data; private MyNode left; private MyNode right; }

  9. 17 を挿入したい 20 29 > > 17 17 29 だから… だから… 20 32 14 < 17 14 24 30 48 だから… 7 19 21 31 19 > 17 だから… 二分探索木へノードの挿入(73ページ以降で詳しく) 29 20 14 19 17

  10. public class BinarySearchTree { public BinarySearchTree() { this.root = null; } private MyNode root; } 二分探索木へ挿入するメソッド public void insert(MyData aData) { MyNode newNode = new MyNode(aData); if(null == this.root){ this.root = newNode; return; } MyNode currentNode = this.root; while(true){ if(0 < currentNode.getData().compareTo(aData)){ if(null == currentNode.getLeft()){ currentNode.setLeft(newNode); return; } currentNode = currentNode.getLeft(); }else{ if(null == currentNode.getRight()){ currentNode.setRight(newNode); return; } currentNode = currentNode.getRight(); } } } 二分探索木を表すクラス

  11. public MyNode search(MyData aData) { if(null == this.root){ return null; } MyNode currentNode = this.root; while(true){ if(0 == currentNode.getData().compareTo(aData)){ return currentNode; } if(0 < currentNode.getData().compareTo(aData)){ if(null == currentNode.getLeft()){ return null; } currentNode = currentNode.getLeft(); }else{ if(null == currentNode.getRight()){ return null; } currentNode = currentNode.getRight(); } } } • ループの終了条件 • 末端に達した • 一致するデータを発見 ループによる二分探索

  12. Tail Recursion(末尾再帰) public MyNode searchRecursive(MyData aData) { return searchR(aData, this.root); } private MyNode searchR(MyData aData, MyNode aRoot) { if(null == aRoot){ // 再帰を終了できるかどうか(末端に到達?)の判定 return null; } int result = aRoot.getData().compareTo(aData); if(0 == result){ // 一致するデータを見つけたかどうかの判定 return aRoot; } return searchR(aData, (0 < result)? aRoot.getLeft(): aRoot.getRight()); } このような再帰呼び出しはループと相互に変換可能

  13. 29 20 32 削除したい 24 14 24 30 48 そのまま削除 削除したい 31 7 19 21 31 削除 子をもたない、または1つだけ持つノードの削除

  14. public boolean remove(MyData aData) { if(null == this.root){ return false; } MyNode parentNode = this.root; MyNode currentNode = this.root; boolean inLeftSubTree = false; while(0 != currentNode.getData().compareTo(aData)){ parentNode = currentNode; if(0 < currentNode.getData().compareTo(aData)){ currentNode = currentNode.getLeft(); inLeftSubTree = true; }else{ currentNode = currentNode.getRight(); inLeftSubTree = false; } if(null == currentNode){ return false; } } /* 削除処理本体は次以降のページで */ currentNode.setLeft(null); currentNode.setRight(null); return true; } 削除対象を探す

  15. if((null == currentNode.getLeft()) && (null == currentNode.getRight())){ if(currentNode == this.root){ this.root = null; }else if(inLeftSubTree){ parentNode.setLeft(null); }else{ parentNode.setRight(null); } }else if(null == currentNode.getRight()){ if(currentNode == this.root){ this.root = currentNode.getLeft(); }else if(inLeftSubTree){ parentNode.setLeft(currentNode.getLeft()); }else{ parentNode.setRight(currentNode.getLeft()); } }else if(null == currentNode.getLeft()){ if(currentNode == this.root){ this.root = currentNode.getRight(); }else if(inLeftSubTree){ parentNode.setLeft(currentNode.getRight()); }else{ parentNode.setRight(currentNode.getRight()); } } /* 続く… */ 親 親 親 子 子 親 親 子 子

  16. 29 削除したい 削除 20 20 32 14 24 30 48 7 19 21 31 子を2つ持つノードの削除

  17. else{ MyNode minimumNode = this.getMinimumNode(currentNode.getRight()); this.remove(minimumNode.getData()); minimumNode.setLeft(currentNode.getLeft()); minimumNode.setRight(currentNode.getRight()); if(currentNode == this.root){ this.root = minimumNode; }else if(inLeftSubTree){ parentNode.setLeft(minimumNode); }else{ parentNode.setRight(minimumNode); } } • 右部分木から最小の(最左)のノードを取り出す • 削除対象と付け替え 親 親 private MyNode getMinimumNode(MyNode aLocalRootNode){ if(null == aLocalRootNode){ return null; } MyNode currentNode = aLocalRootNode; while(true){ if(null == currentNode.getLeft()){ return currentNode; } currentNode = currentNode.getLeft(); } } 子 子 子 子 孫 孫

  18. 29 20 32 14 24 30 48 7 19 21 31 行きがけ順(pre-order)の走査 • 二分木を次のルールで走査 • 自分を訪ねる • 自分の左部分木をたどる • 自分の右部分木をたどる 29 20 32 public void printTreePreOrder() { System.out.println(this.traversePreOrder(this.root)); } private String traversePreOrder(MyNode aLocalRootNode) { if(null == aLocalRootNode){ return ""; } StringBuffer treeRepresentation = new StringBuffer(); treeRepresentation.append(aLocalRootNode + System.getProperty("line.separator")); treeRepresentation.append(this.traversePreOrder(aLocalRootNode.getLeft())); treeRepresentation.append(this.traversePreOrder(aLocalRootNode.getRight())); return treeRepresentation.toString(); } 14 24 30 48 7 19 21 31

  19. 29 20 32 14 24 30 48 7 19 21 31 通りがけ順(in-order)の走査 • 二分木を次のルールで走査 • 自分の左部分木をたどる • 自分を訪ねる • 自分の右部分木をたどる • 二分探索木を走査すると • 整列済みデータが得られる 29 20 32 public void printTreeInOrder() { System.out.println(this.traverseInOrder(this.root)); } private String traverseInOrder(MyNode aLocalRootNode) { if(null == aLocalRootNode){ return ""; } StringBuffer treeRepresentation = new StringBuffer(); treeRepresentation.append(this.traverseInOrder(aLocalRootNode.getLeft())); treeRepresentation.append(aLocalRootNode +System.getProperty("line.separator")); treeRepresentation.append(this.traverseInOrder(aLocalRootNode.getRight())); return treeRepresentation.toString(); } 14 24 30 48 7 19 31 21

  20. 29 20 32 14 24 30 48 7 19 21 31 帰りがけ順(post-order)の走査 • 二分木を次のルールで走査 • 自分の左部分木をたどる • 自分の右部分木をたどる • 自分を訪ねる 29 20 32 public void printTreePostOrder() { System.out.println(this.traversePostOrder(this.root)); } private String traversePostOrder(MyNode aLocalRootNode) { if(null == aLocalRootNode){ return ""; } StringBuffer treeRepresentation = new StringBuffer(); treeRepresentation.append(this.traversePostOrder(aLocalRootNode.getLeft())); treeRepresentation.append(this.traversePostOrder(aLocalRootNode.getRight())); treeRepresentation.append(aLocalRootNode + System.getProperty("line.separator")); return treeRepresentation.toString(); } 14 24 30 48 7 19 21 31

More Related