【问题标题】:Ruby Binary Heap insertion and finding dilemmaRuby Binary Heap 插入和发现困境
【发布时间】:2017-05-20 13:00:21
【问题描述】:

我在构建堆时遇到了一个有趣的问题(不使用数组的挑战),想知道是否有人可以提供帮助。到目前为止,我可以插入许多已构建的节点,并且我的堆结构可以通过我的输出正确构建。但是,当我转到#find 特定节点时,我收到nil,因为我的节点似乎与输出的树不匹配。尽量精简,以下是我所拥有的:

节点构造函数和HeapTree #insert方法

class Node
  attr_accessor :title
  attr_accessor :rating
  attr_accessor :parent
  attr_accessor :left
  attr_accessor :right

  def initialize(title, rating)
    @title = title
    @rating = rating
    @parent = nil
    @left = nil
    @right = nil
  end
end

class HeapSearchTree

  def initialize
    @root = nil
    @heapsize = 1
  end

  def insert(node)
    return nil if node.nil?

    if @root.nil?
      @root = node
    else
      current = @root
      @heapsize += 1 #every insert increases heapsize; used for balancing heap
      until current.left.nil? || current.right.nil?
        if @heapsize % 2 == 0
          current = current.left
        else
          current = current.right
        end
      end

      #after figuring out to go left or right, find the first nil spot
      if current.left.nil? && current.right.nil?
        current.left = node
        node.parent = current
      elsif current.left.nil? && !current.right.nil?
        current.left = node
        node.parent = current
      elsif !current.left.nil? && current.right.nil?
        current.right = node
        node.parent = current
      end

      #heapify by swapping titles and ratings because if I swap parent node for higher node it doesnt stick.
      while node.rating >= node.parent.rating
        if node.parent.rating <= node.parent.left.rating
          temp_title = node.parent.title
          temp_rating = node.parent.rating

          node.parent.title = node.parent.left.title
          node.parent.rating = node.parent.left.rating
          node.parent.left.title = temp_title
          node.parent.left.rating = temp_rating
        elsif node.parent.rating <= node.parent.right.rating
          temp_title = node.parent.title
          temp_rating = node.parent.rating

          node.parent.title = node.parent.right.title
          node.parent.rating = node.parent.right.rating
          node.parent.right.title = temp_title
          node.parent.right.rating = temp_rating
        end
      end
    end
  end
  def find(root=@root, movie_title)
    if root.title == movie_title
      puts "END OF RECURSION"
      puts "movie_title entered: #{movie_title}"
      puts "root.title: #{root.title}"
      return root
    else
      loop = 0
      left = find(root.left, title) if root.left
      right = find(root.right, title) if root.right
      left || right
      loop += 1
      puts loop
    end
  end

问题图片

您会注意到插入martian,树会正确重新排列。但是,当我 tree.find(matrix.title) 它作为 martian.title 传入时,我得到 nil 作为回报。

我对此感到困惑一段时间,无法通过网络找到任何可以帮助我的东西。如果node.parent 的评分低于node,我将用node.parent 交换标题和评分。 node ID 没有改变,只是信息。寻找解决方案来完成这项工作。大多数会显示一个内置数组,但我不想将数组用于学习目的。谢谢

注意

我发现我的程序从#insert 中的while 循环冒泡中中断。我现在正在尝试移动 nodenode.parent,但证明同样困难。

【问题讨论】:

  • 我注意到的一件事是,当您添加第一个节点时,您并没有增加 @heapsize,所以您的大小似乎是一次性的?
  • @heapsize 正在改变。当我重新排列标题和评级时,我的问题在#insert 内部。不幸的是,它以某种方式改变了我的对象数据。如果我在插入martianputs matrix.titlematrix.title = martian.title
  • 您正在构建的是某种二叉树,但它肯定不是我所知道的任何一种heap。这绝对不是binary heap。此外,堆并不是一个特别好的搜索数据结构,因为您必须对树进行详尽的搜索。你想用这个“堆”解决什么问题?
  • 这是一个二叉最大堆树,您可以将.ratings 视为我正在尝试构建的层次结构。二进制部分已完成,但现在我正在尝试通过.rating 组织我的树。大多数人创建这些我注意到使用数组或队列,但我试图通过parentleftright 来解决它。树形成正确,但我的ratings 没有像应有的那样冒泡。
  • 我不相信您的 insert 方法会根据二叉树的规则正确确定插入点。更简单(并且可以证明是正确的)方法是使用节点数来计算通过树的路径。然后在叶级插入新节点并将其筛选up。有关示例,请参见 stackoverflow.com/q/40586802/56778

标签: ruby-on-rails ruby heap binary-tree


【解决方案1】:

通过重新创建 #insert

解决了我的问题
def insert(root, node)
    root = @root
    current = @root
    @heapsize += 1 #every insert increases heapsize; used for balancing heap

    until current.left.nil? || current.right.nil?
      if @heapsize % 2 == 0
        current = current.left
      else
        current = current.right
      end
    end

    if current.left.nil? && current.right.nil?
      current.left = node
      node.parent = current
    elsif current.left.nil? && !current.right.nil?
      current.left = node
      node.parent = current
    elsif !current.left.nil? && current.right.nil?
      current.right = node
      node.parent = current
    end

  #if rating > (greater than) its parents rating 
    while node.rating >= node.parent.rating
      loop = 1
      temp_parent = node.parent
      temp_parent_right = node.parent.right
      temp_parent_left = node.parent.left
      temp_node_left = node.left
      temp_node_right = node.right
  # if node is greater then its parent and node is to the left of parent
      if node.parent.parent.nil? && node == node.parent.left
        puts "im here on left and parents parent is nil"
        node.right = node.parent.right
        node.parent = node.parent.parent
        node.left = temp_parent

        node.left.parent = node
        node.left.left = temp_node_left
        node.left.right = temp_node_right

        if !node.right.nil?
          node.right.parent = node
        end

        @root = node
        break
  # if node is greater then its parent and node is to the right of parent
      elsif node.parent.parent.nil? && node == node.parent.right
        puts "im here on right and parents parent is nil"

        node.left = node.parent.left
        node.parent = node.parent.parent 
        node.right = temp_parent 

        node.right.parent = node
        node.right.right = temp_node_right
        node.right.left = temp_node_left
        node.left.parent = node

        @root = node
        break


      elsif !node.parent.nil? && node == node.parent.left
        puts "im here on left and my parents parent is not nil"

        if node.parent.parent.left == node.parent
          node.parent.parent.left = node
          node.parent.parent.left.parent = node.parent.parent
          node.left = temp_parent
          node.right = temp_parent_right
          node.left.parent = node
          unless node.right.nil?
            node.right.parent = node
          end
          node.left.left = temp_node_left
          node.left.right = temp_node_right
        elsif node.parent.parent.right == node.parent
          node.parent.parent.right = node
          node.parent.parent.right.parent = node.parent.parent
          node.left = temp_parent
          node.right = temp_parent_right
          node.left.parent = node
          unless node.right.nil?
            node.right.parent = node
          end
          node.left.left = temp_node_left
          node.left.right = temp_node_right
        end

      elsif !node.parent.nil? && node == node.parent.right

        if node.parent.parent.right == node.parent
          node.parent.parent.right = node
          node.parent.parent.right.parent = node.parent.parent
          node.right = temp_parent
          node.left = temp_parent_right
          node.right.parent = node
          unless node.left.nil?
            node.left.parent = node
          end
          node.left.left = temp_node_left
          node.left.right = temp_node_right
        elsif node.parent.parent.left == node.parent
          node.parent.parent.left = node
          node.parent.parent.left.parent = node.parent.parent
          node.left = temp_parent
          node.left = temp_parent_right
          node.right.parent = node
          unless node.right.nil?
            node.right.parent = node
          end
          node.left.left = temp_node_left
          node.left.right = temp_node_right
        end

      end
    end
  end

【讨论】:

    【解决方案2】:

    这是正确的,因为HeapSearchTree#insert 会改变节点而不是正确交换它们。您的插入代码会改变节点的标题和评级。变量matrix 绑定到标题为“The Matrix”的节点,但通过插入方法将其更改为“The Martian”。

    [2] pry(main)> tree = HeapSearchTree.new
    [3] pry(main)> matrix = Node.new("The Matrix", 87)
    [4] pry(main)> martian = Node.new("The Martian", 92)
    
    [5] pry(main)> tree.insert(matrix)
    => #<Node:0x007f92348c7c10
     @left=nil,
     @parent=nil,
     @rating=87,
     @right=nil,
     @title="The Matrix">
    [6] pry(main)> matrix.object_id
    => 70132961787400
    [7] pry(main)> matrix.title
    => "The Matrix"
    
    [8] pry(main)> tree.insert(martian)
    => nil
    
    [9] pry(main)> matrix.object_id
    => 70132961787400
    [10] pry(main)> matrix.title
    => "The Martian"
    
    [11] pry(main)> tree.find(matrix.title)
    END OF RECURSION
    movie_title entered: The Martian
    root.title: The Martian
    

    这表明绑定到变量matrix 的节点正在显示正确的标题,因此搜索该标题会返回正确的结果。正如您所提到的,我会重新实现插入以正确交换节点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-17
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多