バイナリツリーの再設計
日本Rubyの会 公式Wiki - Ruby勉強会@関西-17で添削していたバイナリツリーのプログラムを仕様の継承をあきらめて再設計したらどうなるかなと思ってやってみました。どことなく関数型のにおいがします。
module BinaryTree def to_tree(ns) ns.inject(Node.new) {|tree, n| tree << n } end module_function :to_tree class Node def initialize(data = nil) @data = data @left = nil @right = nil end def <<(data) case when @data.nil? then @data = data when @data == data then # ignore when @data > data then (@left ||= Node.new) << data when @data < data then (@right ||= Node.new) << data end self end def trace(data) case when @data.nil? then '*' when @data == data then @data.inspect when @data > data then @left ? "#{@data}-L-#{@left.trace(data)}" : '*' when @data < data then @right ? "#{@data}-R-#{@right.trace(data)}" : '*' end end end end if $0 == __FILE__ ns = [17, 20, 13, 32, 47, 9, 50, 48] puts ns.join(' ') # => 17 20 13 32 47 9 50 48 tree = BinaryTree.to_tree(ns) puts tree.trace(50) # => 17-R-20-R-32-R-47-R-50 puts tree.trace(1) # => 17-L-13-L-* puts tree.trace(9) # => 17-L-13-L-9 end
以下、変更点というか設計時に気を付けたこと。
- 全体をmoduleにして、バイナリツリー生成用のメソッドを持たせました。
- ツリーの節はNodeクラスにしました。
- 追加するメソッド名を<<にしてselfを返すようにしました。tree << 1 << 2 << 3みたいに使えるように。
- IOを分離するため、traceメソッドは文字列を返すようにしました。このため、見付かったか見付からないかは、traceメソッドではわからなくなりました。これについては別途メソッドを設けた方がよいように思います。