LoginSignup
3

More than 3 years have passed since last update.

アルゴリズムとデータ構造の要点メモ in ruby(二分木)

Last updated at Posted at 2019-09-22

目的

技術面接のために修行を始める。
ウェブでの技術試験時にみやすいようにこのページにまとめる。
Rubyでそそくさと実装できることを目的とする。

配列 https://qiita.com/tsnb/items/983c32d83331de1e0bea
連結リスト https://qiita.com/tsnb/items/3028ee788ff77ebaaa5e
スタック https://qiita.com/tsnb/items/e6901249629ef090ee8f
キュー https://qiita.com/tsnb/items/588afe675ad830ff1fc6

参考

二分木(データ構造)

要点

二分木とは、葉以外のすべての節が、2つ以下の子を持つような木構造、
必ず2つの子を持つようならば、全二分木、
どの葉も同じ深さにある場合は、完全二分木

struct Node_tag {
    int                   value;
    struct Node_tag*      left;
    struct Node_tag*      right;
};
  • 木構造は、親をたどる必要性がない場合もよくある

アルゴリズム

走査(トラバース)

「すべてをもらさず」「同じものを重複せず」に、二分木に含まれるすべての節を調べたい

  • 探索方法
    • 深さ優先探索
      • 行きがけ順探索 pre
      • 通りがけ順探索 in => 結果がソートされている
      • 帰りがけ順探索 post
    • 幅優先探索

深さ優先探索の実装

  • まずは深さ優先探索を実装
  • add_left, add_rightで木を追加
  • pre, in, postを実装
  • 再帰で実装、スタックとループは余力があれば・・
class Node
  attr_accessor :val, :left, :right

  def initialize(val)
    @val = val
    @left = nil
    @right = nil
  end

  def add_left(val)
    self.left = Node.new(val)
  end

  def add_right(val)
    self.right = Node.new(val)
  end
end

class BinaryTree
  attr_reader :head, :list

  def initialize(val)
    @head = Node.new(val)
    @list = []
  end

  def pre
    @list = []
    traverse(@head, :pre)
    @list
  end

  def in
    @list = []
    traverse(@head, :in)
    @list
  end

  def post
    @list = []
    traverse(@head, :post)
    @list
  end

private
  def traverse(node, type=:pre)
    @list << node.val             if type == :pre
    traverse(node.left, type)     if !!node.left
    @list << node.val             if type == :in
    traverse(node.right, type)    if !!node.right
    @list << node.val             if type == :post
  end
end

手動で木を作って、探索〜
以下の資料の木構造と同じように作って結果も一致することを確認した
http://www-ikn.ist.hokudai.ac.jp/~arim/pub/algo/algo6.pdf

irb(main):270:0> bt = BinaryTree.new(7)
=> #<BinaryTree:0x00007fa0cf86fc78 @head=#<Node:0x00007fa0cf86fc50 @val=7, @left=nil, @right=nil>, @list=[]>
irb(main):271:0> bt.head.add_left(3)
=> #<Node:0x00007fa0cf86c4b0 @val=3, @left=nil, @right=nil>
irb(main):272:0> bt.head.left.add_left(1)
=> #<Node:0x00007fa0cf864648 @val=1, @left=nil, @right=nil>
irb(main):273:0> bt.head.left.add_right(4)
=> #<Node:0x00007fa0d082c648 @val=4, @left=nil, @right=nil>
irb(main):274:0> bt.head.left.right.add_right(6)
=> #<Node:0x00007fa0cf85ff80 @val=6, @left=nil, @right=nil>
irb(main):275:0> bt.head.left.right.right.add_left(5)
=> #<Node:0x00007fa0cf853000 @val=5, @left=nil, @right=nil>
irb(main):276:0> bt.head.add_right(10)
=> #<Node:0x00007fa0ce8cb858 @val=10, @left=nil, @right=nil>
irb(main):277:0> bt.head.right.add_left(8)
=> #<Node:0x00007fa0d0827490 @val=8, @left=nil, @right=nil>
irb(main):278:0> bt
=> #<BinaryTree:0x00007fa0cf86fc78 @head=#<Node:0x00007fa0cf86fc50 @val=7, @left=#<Node:0x00007fa0cf86c4b0 @val=3, @left=#<Node:0x00007fa0cf864648 @val=1, @left=nil, @right=nil>, @right=#<Node:0x00007fa0d082c648 @val=4, @left=nil, @right=#<Node:0x00007fa0cf85ff80 @val=6, @left=#<Node:0x00007fa0cf853000 @val=5, @left=nil, @right=nil>, @right=nil>>>, @right=#<Node:0x00007fa0ce8cb858 @val=10, @left=#<Node:0x00007fa0d0827490 @val=8, @left=nil, @right=nil>, @right=nil>>, @list=[]>
irb(main):279:0> bt.pre
=> [7, 3, 1, 4, 6, 5, 10, 8]
irb(main):280:0> bt.in
=> [1, 3, 4, 5, 6, 7, 8, 10]
irb(main):281:0> bt.post
=> [1, 5, 6, 4, 3, 8, 10, 7]

幅優先探索の実装

  • キューと再帰で実装
class Node
  attr_accessor :val, :left, :right

  def initialize(val)
    @val = val
    @left = nil
    @right = nil
  end

  def add_left(val)
    self.left = Node.new(val)
  end

  def add_right(val)
    self.right = Node.new(val)
  end
end

class BinaryTree
  attr_reader :head, :list

  def initialize(val)
    @head = Node.new(val)
    @list = []
    @queue = []
  end

  def bfs
    @list = []
    traverse(@head)
  end

private
  def traverse(node)
    return @list if node.nil?

    @list << node.val
    @queue << node.left if !!node.left
    @queue << node.right if !!node.right
    node = @queue.shift
    traverse(node)
  end
end
irb(main):136:0> bt = BinaryTree.new(7)
=> #<BinaryTree:0x00007fbd20833850 @head=#<Node:0x00007fbd20833828 @val=7, @left=nil, @right=nil>, @list=[], @queue=[]>
irb(main):137:0> bt.head.add_left(3)
=> #<Node:0x00007fbd20841220 @val=3, @left=nil, @right=nil>
irb(main):138:0> bt.head.left.add_left(1)
=> #<Node:0x00007fbd2082aa70 @val=1, @left=nil, @right=nil>
irb(main):139:0> bt.head.left.add_right(4)
=> #<Node:0x00007fbd1f0c3f08 @val=4, @left=nil, @right=nil>
irb(main):140:0> bt.head.left.right.add_right(6)
=> #<Node:0x00007fbd1f0b8d38 @val=6, @left=nil, @right=nil>
irb(main):141:0> bt.head.left.right.right.add_left(5)
=> #<Node:0x00007fbd1f0a8870 @val=5, @left=nil, @right=nil>
irb(main):142:0> bt.head.add_right(10)
=> #<Node:0x00007fbd1f093d30 @val=10, @left=nil, @right=nil>
irb(main):143:0> bt.head.right.add_left(8)
=> #<Node:0x00007fbd1f080708 @val=8, @left=nil, @right=nil>
irb(main):144:0> bt.bfs
=> [7, 3, 10, 1, 4, 8, 6, 5]

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3