Ruby,这个二叉树是正确的吗?

时间:2018-05-16 13:27:27

标签: ruby binary-search-tree

所以我要通过OdinProject并开始使用" BinaryTree"一部分。我编写了一个二叉树,但只能用C ++编写指针。因此,如果没有指针,我对节点的连接方式会更加困惑:

class Node

  attr_accessor :value, :parent, :left, :right
  @@nodes = 0

  def self.nodes
    @@nodes
  end

  def initialize(value, parent=nil)
    @value = value
    @parent = parent
    @left = nil
    @right = nil
    @@nodes += 1
  end

end


class BinaryTree

  def initialize
    @root = nil
  end

  def build_tree(arr)
    arr.each {|el| add_child(el,@root)}
    @root
  end

  def add_child(value,node)
    if @root.nil?
      @root = Node.new(value)
    else
      if value < node.value
        node.left.nil? ? node.left = Node.new(value,node) : add_child(value,node.left)
      elsif value > node.value
        node.right.nil? ? node.right = Node.new(value,node) : add_child(value,node.right)
      end
    end
    return node
  end

end

我已经完成了一些基本的打印功能,并且SEEMS正常工作,但我想知道这对于更了解ruby的其他人是否正确。 (旁注:我意识到这不能处理重复的数字)。我错过了&#34;建筑&#34;树的一部分。

我担心的原因是看到很多不同的&#34; build&#34;实现。例如,从中点开始,或仅仅是为了#34;排序&#34;阵列

1 个答案:

答案 0 :(得分:2)

欢迎来到红宝石世界!要小心你可能真的喜欢它,永远不会回到另一种语言:)

以下是我可以给你的一些评论:

测试

当你想知道你的代码是否正确时,首先要用不同的输入来测试它。您可以在控制台中手动完成,也可以编写将在开发过程中跟随您的测试。

通过打印

快速测试您的工作方法是在to_s课程中定义Node方法。例如,这将允许检查您的树是否已订购:

class Node
  …
  def to_s
     "#{left} #{value} #{right}".strip
  end
end 

to_s是将对象转换为字符串时使用的默认ruby方法。例如,你可以这样做:

#> puts BinaryTree.new.build_tree([5, 9, 1, 6])
1 5 6 9

通过测试

为了您的安心,您可以描述一些测试,这些测试将允许您编写代码并对其进行修改,并检查它是否仍然有效。我建议minitest很容易做到。

require 'minitest/autorun'

describe BinaryTree do
  before do
    @constructor = BinaryTree.new
  end

  describe 'when given an array' do
    it 'sorts it' do
      @constructor.build_tree([1, 3, 2]).to_s.must_equal '1 2 3'
    end
  end

  describe 'when given an array with duplicates' do
    it 'builds the correct tree' do
      @constructor.build_tree([1, 3, 2, 3]).to_s.must_equal '1 2 3 3'
    end
  end
end

如果ruby -Ilib:test binary_tree.rb是放置代码的文件,则可以使用binary_tree.rb运行它。

正如您所提到的,您将看到重复的代码不起作用。 您可以通过删除if…elsif块中的条件来使其工作。

然后,您可以根据需要随时处理代码并运行测试,以确保您没有破坏任何内容。

每次有边缘情况时,您都不确定代码是否处理,只需将其置于测试中即可。

计算节点

如果计算二叉树中的节点数,那么Node.nodes方法可能不是您想要的。 它应该在Node的实例中,而不是在类本身中:如果您有多个树,则每个树都会考虑所有节点。

Ruby的东西

你写的一些内容在ruby中可能有不同的表达方式:

没有必要

attr_accessor parent

的语法糖
def parent
  @parent
end

def parent=(other)
  @parent = other
end

在ruby中,如果未声明实例变量@parent,则默认值为nil,调用node.parent也会返回nil

初始化程序中不需要这两行:

@left = nil
@right = nil

无需返回

如果方法中的最后一条指令是退货,则不需要return关键字。这就是我用上面的to_s方法做的。

命名参数

我认为当命名参数不明显时更清晰。 例如,调用Node.new(value, node)并不能真正帮助理解这两个参数是什么。我得到一个节点应该有一个值,但第二个参数是什么?

您可以定义:

def initialize(value, parent: nil)
  # Same as before
end

并使用Node.new(value, parent: node)Node.new(value)

进行调用

OO的东西

移动他们所属的方法

您的BinaryTree#add_child方法应该在节点上。您正在向节点添加子项。移动它,所以你不需要你的第二个参数: add_child(value, node.right)变为node.right.add_child(value)

class Node
  ...
  def add_child(other_value)
    if other_value < value
      left.nil? ? self.left = Node.new(other_value, parent: self) : left.add_child(other_value)
    else
      right.nil? ? self.right = Node.new(other_value, parent: self) : right.add_child(other_value)
    end
  end
end

class BinaryTree
  ...
  def add_child(value)
    if @root.nil?
      @root = Node.new(value)
    else
      @root.add_child(value)
    end
    @root
  end
end

当你在那里时,你也可以摆脱build_tree课程中的BinaryTree,并将其移至Node

我希望它能帮助你完成Ruby之旅。