せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】【アルゴリズム】二分木の実装 追加/削除/検索

二分木とは

二分木は「木構造 (tree structer) 」または「木 (tree) 」と呼ばれるデータ構造の一つです。

http://www.geocities.jp/m_hiroi/light/abcruby13.html

 

学んだこと

再帰コードを書くときに、状態が変わるものをレシーバーにするのは良くない。

例えば今回の二分木実装では、
最初、Treeクラスを作らずにやって手詰まった。

具体的には、最初はこういうコードを書いていた↓

root = Node.new(nil,nil,10)
root.kesu(10)

この方法だと、
レシーバをnilにする必要があるけれども、
kesuメソッドの中ではrootオブジェクトがselfとして参照され、
selfへの代入は出来ないから、だめ。

 Can't change the value of self

 
とりあえず、再帰を書くときはレシーバを意識する。




あと、Rubyの「最後に評価した式が返り値となる仕様」に時たま嵌ってしまう。

例えばこのコード↓、最後のnodeを忘れると再帰がずれてしまう。

  def _delete_max(node)
    return node = node.left if node.right.nil?
    node.right = _delete_max(node.right)
    node
  end


 

作成したコード

class Node
  attr_accessor :left, :right, :val
  def initialize (left, right, val)
    @left = left
    @right = right
    @val = val
  end
end

class BinaryTree
  attr_accessor :root
  def initialize ()
    @root = nil
  end
  def add(int)
    obj = Node.new(nil,nil,int)
    @root = _add(@root, obj)
    self
  end
  def _add(root, obj)
    return root = obj if root.nil?
    if obj.val < root.val
      if !root.left
        root.left = obj
      else
        _add(root.left, obj)
      end
    else
      if !root.right
        root.right = obj
      else
        _add(root.right, obj)
      end
    end
    root
  end
  def _exist(root, int)
    return root if int == root.val
    if int < root.val
      return nil if root.left.nil?
      _exist(root.left, int)
    else
      return nil if root.right.nil?
      _exist(root.right, int)
    end
  end
  def exist(int)
    _exist(@root, int)
  end
  def kesu(int)
    return nil if !exist(int)
    _kesu(@root, int)
  end
  def _kesu(node, int)
    if int == node.val
      return node.right if node.left.nil?
      return node.left if node.right.nil?

      node.val = _biggest(node.left).val
      node.left = _delete_max(node.left)
      p node.left
    elsif int < node.val
      node.left = _kesu(node.left, int)
    else
      node.right = _kesu(node.right, int)
    end
    node
  end
  def _biggest(node)
    return node if node.right.nil?
    _biggest(node.right)
  end
  def _delete_max(node)
    return node = node.left if node.right.nil?
    node.right = _delete_max(node.right)
    node
  end
end

root = BinaryTree.new()
root.add(50)
root.add(10)
root.add(20)
root.add(8)
root.add(60)
p root.kesu(50)


 
■実行結果

#<Node:0x2c21280 @left=#<Node:0x2c21268 @left=#<Node:0x2c21238 @left=nil, @right
=nil, @val=8>, @right=nil, @val=10>, @right=#<Node:0x2c21220 @left=nil, @right=n
il, @val=60>, @val=20>