递归和链表

时间:2015-03-15 07:14:41

标签: ruby list recursion

我希望看到链表的表示。我创建了一个用于创建链表的类:

class LinkedListNode
  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end
  def print_values(list_node)
    print "#{list_node.value} --> "
    if list_node.next_node.nil?
      print "nil"
      return
    else
      print_values(list_node.next_node)
    end
  end

  node1 = LinkedListNode.new(37)
  node2 = LinkedListNode.new(99, node1)
  node3 = LinkedListNode.new(12, node2)
  print_values(node3)
end

我明白了:

practice.rb:24:in `<class:LinkedListNode>': undefined method `print_values' for LinkedListNode:Class (NoMethodError)

递归是一个调用自身的方法吗?有可能让方法调用另一个方法来替换递归吗?或者是在调用另一种不允许的方法?

3 个答案:

答案 0 :(得分:1)

  

递归是一种自我调用的方法吗?

是的,一般而言。有关具体内容,示例和例外情况,请参阅Wikipedia

如果简化方法,您可以在自己的代码中理解递归。

您编写的代码更类似于过程代码,而Ruby通常使用更类似于此的面向对象的代码:

class LinkedListNode

  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end

  # This is how to write a typical Ruby recursive method.
  # Notice the method does something with this object's value,
  # then transfers control to the next object's same method name.

  def to_s
    "#{value} --> " + (next_node ? next_node.to_s : "nil")
  end

end

# This code is moved out of your class definition.
# This fixes one of the errors in your original code.

node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)

print node3.to_s
  

是否可以在另一个方法上调用方法来替换递归?

是的,一般而言。例如,在你的代码中,你可以调用一个使用迭代而不是递归的方法,就像这个例子。

递归:

  def to_s
    "#{value} --> " + (next_node ? next_node.to_s : "nil")
  end

迭代:

  def to_s
    s = ""
    node = self
    while node != nil
      s += "#{value} --> " 
      node = next_node
    end
    s += "nil"
  end

使用迭代实现的算法通常比使用递归实现的类似算法运行得快得多。

某些类型的递归(包括此处的代码)比其他类型的递归更有效。您的代码是可以使用高效tail call optimization

的代码的一个很好的示例

答案 1 :(得分:0)

您的print_values方法是实例方法,但它不使用其中的实例。

我相信您打算使用实例数据进行实施:

class LinkedListNode
  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end
  def print_values
    print "#{value} --> "
    if next_node.nil?
      print "nil"
      return
    else
      next_node.print_values
    end
  end
end

node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)
node3.print_values

另一种选择是使方法成为 static 方法,该方法不需要实例,如下所示:

class LinkedListNode
  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end
  def self.print_values(list_node)
    print "#{list_node.value} --> "
    if list_node.next_node.nil?
      print "nil"
      return
    else
      print_values(list_node.next_node)
    end
  end
end

  node1 = LinkedListNode.new(37)
  node2 = LinkedListNode.new(99, node1)
  node3 = LinkedListNode.new(12, node2)
  LinkedListNode.print_values(node3)

这两个选项都将被视为递归,因为该方法会调用自身。没有关于递归的规则(允许调用另一种方法),但有些事情你需要注意,比如你没有良好的停止条件,你的方法可能& #34;爆炸&#34;堆栈溢出异常。

答案 2 :(得分:-1)

您应该将处理类的代码移出类定义:

class LinkedListNode

  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end

  def print_values(list_node)
    print "#{list_node.value} --> "
    if list_node.next_node.nil?
        print "nil"
        return
    else
        print_values(list_node.next_node)
    end
  end
end

node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)

node3.print_values(node3)

代码有一些其他毛刺,比如print_values是一个类方法,而不是实例方法,但主要问题在于上面。这就是我将代码转换为使用类方法打印值的方法:

class LinkedListNode

  attr_accessor :value, :next_node

  def initialize(value, next_node = nil)
    @value = value
    @next_node = next_node
  end 

  def self.print_values list_node
    print "#{list_node.value} --> "
    if list_node.next_node.nil?
        print "nil"
        return
    else
        print_values(list_node.next_node)
    end 
  end 
end

node1 = LinkedListNode.new(37)
node2 = LinkedListNode.new(99, node1)
node3 = LinkedListNode.new(12, node2)

LinkedListNode.print_values node3

希望它有所帮助。

NB @joelparkerhenderson提供的答案实际上更好。