добро пожаловать в мир рубинов!Остерегайтесь, вам это действительно может понравиться, и вы никогда не вернетесь к другому языку:)
Вот несколько комментариев, которые я могу вам дать:
Тестирование
Первое, когда вам интересноКод правильный, чтобы проверить его с разными входами.Вы можете сделать это вручную, в консоли или написать тесты, которые будут следовать за вами во время разработки.
Путем печати
Быстрый способ тестирования того, что вы делаете, - определить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:
Nil не требуется
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)
на самом деле не помогает понять, для чего эти 2 параметра.Я получаю, что узел должен иметь значение, но что это за второй параметр?
Вы можете определить:
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.