ツリー構造(2分木)

7月 6th, 2008 admin Posted in アルゴリズムとデータ構造 |

今回も「アルゴリズムとデータ構造シリーズ」です。本日は「ツリー構造」について。

ツリー構造とは

ツリー構造とは樹形図のようになったデータ構造のことです。Windowsのファイル構造はツリー構造ですね。
難しそうに感じますが、以前やったリスト構造では、データが次のノードへのポインタを一つしかもっていなかったものを複数にするというだけで実現できます。

2分木

今回はツリー構造の中でも2分木と呼ばれるものを実装しました。2分木とはツリー構造の中でも各ノードが最大2個の子ノードしかもたない構造のことです。さらに今回は2分木の中でも、子ノードの並べ方に順序をつけ検索性をアップしたタイプ(左が小さい、右が大きい)にし、挿入・検索・削除ができるようにしました。
binarytree.png

まとめ

挿入や、検索よりも削除が面倒でした。
ツリー構造にはいろいろな応用パターンがあっておくが深そうです。本書では常に検索効率の良いAVL木やデータベースエンジンでよく使用されているB木(B+木)の解説もあり非常に勉強になりました。

コード

今回はコードが長いので最後にしました

RUBY:
  1. #Binary Tree
  2. $KCODE = "SJIS"
  3.  
  4. class Node
  5.   attr_accessor :left,:right,:value
  6.   def initialize(value)
  7.     @value = value
  8.     @left = nil
  9.     @right = nil
  10.   end
  11. end
  12.  
  13. class BinaryTree
  14.   attr_accessor :tree_root
  15.  
  16.   def initialize
  17.     @tree_root = nil
  18.   end
  19.  
  20.   def create_new_node(value)
  21.     Node.new(value)
  22.   end
  23.  
  24.   def insert_tree(value, node)
  25.     if node.nil?
  26.       @tree_root = self.create_new_node(value)
  27.       return
  28.     end
  29.    
  30.     if node.value> value
  31.       unless node.left.nil?
  32.         self.insert_tree(value,node.left)
  33.       else
  34.         node.left = self.create_new_node(value)
  35.       end
  36.     else
  37.       unless node.right.nil?
  38.         self.insert_tree(value,node.right)
  39.       else
  40.         node.right = self.create_new_node(value)
  41.       end
  42.     end
  43.   end
  44.  
  45.   def find(node, value)
  46.     if node.value> value
  47.       return nil if node.left.nil?
  48.       return self.find(node.left, value)
  49.     end
  50.    
  51.     if node.value <value
  52.       return nil if node.right.nil?
  53.       return self.find(node.right, value)
  54.     end
  55.  
  56.     node
  57.   end
  58.  
  59.   def delete(value)
  60.     direction = 0
  61.     parent_node = nil
  62.     node = @tree_root
  63.    
  64.     while(node != nil && node.value != value) do
  65.       if(node.value> value)
  66.         parent_node = node
  67.         node = node.left
  68.         direction = -1
  69.       else
  70.         parent_node = node
  71.         node = node.right
  72.         direction = 1
  73.       end 
  74.     end
  75.    
  76.     return 0 if node.nil?
  77.  
  78.     if(node.left.nil? || node.right.nil?)
  79.       #左右どちらかがnilだった場合
  80.       if(node.left.nil?)
  81.         parent_node.left = node.right if direction == -1
  82.         parent_node.right = node.right if direction == 1
  83.         @tree_root = node.right if direction == 0
  84.       else
  85.         parent_node.left = node.left if direction == -1
  86.         parent_node.right = node.left if direction == 1
  87.         @tree_root = node.left if direction == 0
  88.       end
  89.     else
  90.       #両者共nilでなかった場合
  91.       left_biggest = node.left
  92.       parent_node = node
  93.       direction = -1
  94.       while(left_biggest.right != nil) do
  95.         parent_node = left_biggest
  96.         left_biggest = left_biggest.right
  97.         direction = 1
  98.       end
  99.      
  100.       node.value = left_biggest.value
  101.       if(direction == -1)
  102.         parent_node.left = left_biggest.left
  103.       else
  104.         parent_node.right = left_biggest.left
  105.       end
  106.     end
  107.     true
  108.   end
  109.  
  110.   def print_tree(depth, node)
  111.     return if node.nil?
  112.    
  113.     self.print_tree(depth+1, node.left)
  114.     (0...depth).each{|i|
  115.       printf("    ")
  116.     }
  117.     printf("%d\n",node.value)
  118.     self.print_tree(depth+1,node.right)
  119.   end
  120. end
  121.  
  122. tree = BinaryTree.new
  123. 10.times{|i|
  124.   tree.insert_tree(rand(99),tree.tree_root)
  125. }
  126. tree.print_tree(0,tree.tree_root)
  127.  
  128. i = nil
  129. while i != 0 do
  130.   print "現在のツリー\n"
  131.   tree.print_tree(0,tree.tree_root)
  132.  
  133.   print "コマンドを入力して下さい\n0:終了 1:追加 2:検索 3:削除\n"
  134.   i = gets.chomp.to_i
  135.  
  136.   case i
  137.     when 1
  138.       print "1~100の範囲で、追加する数字を入力してください:"
  139.       j = gets.chomp.to_i
  140.       tree.insert_tree(j ,tree.tree_root) if (j>= 1 && j <= 100)
  141.     when 2
  142.       print "検索する数字を入力してください:"
  143.       j = gets.chomp.to_i
  144.       if tree.find(tree.tree_root,j)
  145.         printf("%dは見つかりました。 \n",j)
  146.       else
  147.         print("見つかりませんでした。\n")
  148.       end
  149.     when 3
  150.       print "削除する数字を入力してください:"
  151.       j = gets.chomp.to_i
  152.       if tree.delete(j)
  153.         printf("%dは削除しました。 \n",j)
  154.       else
  155.         print("見つかりませんでした。\n")
  156.       end   
  157.   end
  158. end

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

2 Responses to “ツリー構造(2分木)”

  1. [...] 2分木(binary tree) はてなに追加 MyYahoo!に追加 del.icio.usに追加 livedoorClipに追加 10 Responses to “Rubyでアルゴリズムとデータ構造” [...]

  2. [...] まず前章でやったツリー構造を使うのがツリーマップである。キーとなる文字列をstrcmp()関数などで数値化して2分木で保持するというものだ。ツリーのどこにデータがあるかによって計算時間にばらつきがでるので安定していないのが欠点である。 [...]

Leave a Reply