【问题标题】:In binary tree insertion, only the left tree is right. The right tree is wrong在二叉树插入中,只有左树是正确的。正确的树是错误的
【发布时间】:2019-12-16 12:27:58
【问题描述】:

我有一个 btree 类和一个插入函数,可以将节点插入到树中,广度明智。但是树没有在右侧插入节点。

我正在创建根节点。 insert函数将左右节点正确插入根节点。

然后递归地,我尝试在左节点插入两个节点,在右节点插入两个节点。但是在这一步中,所有节点只添加到左侧。节点也被添加到 None 父节点。

我知道,我在插入函数中的最后一个 else 语句中犯了一个错误。但是我尝试了很多组合,但都导致了一些错误。

class BinTree(object):
  def __init__(self, val):
    self.val = val
    self.left = None
    self.right = None

  def insert(self,val):
    if self.left is None:
      self.left = BinTree(val)
    elif self.right is None:
      self.right = BinTree(val)
    elif self.left:
      self.left.insert(val)
    else:
      self.right.insert(val)

root = BTree('A')
root.insert('B')
root.insert('C')
root.insert(None)
root.insert('D')
root.insert(None)
root.insert('E')
root.insert('F')
Expected:
                 A
              /     \
             B       C
            /\       /\
        None  D  None  E
             /
            F

Getting:
                 A
              /     \
             B       C
            / \
        None   D
         /  \
     None    E
       /
      F

【问题讨论】:

  • 您能否用insert() 中的那些if 语句来告诉我们您的思考过程?
  • 欢迎来到 SO!需要考虑的几件事:B-tree 不是二叉树。看起来您正在尝试创建二叉树,因此如果该类称为BTree,会令人困惑。其次,我没有看到任何 Node 类,因此该示例不起作用。你能澄清你的意图吗?最后,正如迈克尔上面所说的,想想if 语句在做什么,尤其是第三个。什么时候会是假的?就本示例而言,使用 None 是一个令人困惑的值名称,建议始终使用唯一字母。
  • 在代码块中正确格式化你的树的道具。大多数人都懒得这样做(尽管他们应该这样做)。
  • @asciillatin 是否有任何答案解决了您的问题?
  • None是什么意思?

标签: python recursion data-structures tree binary-tree


【解决方案1】:

使用您保存的当前字段进行递归并不能真正得到您想要的结果。每个节点只“知道”它的当前状态,这就是为什么树的右侧将永远保持在深度 1。

想到的一个解决方案是添加right childrenleft children 金额字段。这将有助于跟踪余额。它看起来像这样:

 class Node(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        self.right_count = 0
        self.left_count = 0
        self.even_depth = True
        self.needed_to_even = 1

    def insert(self, val):
        if self.left is None:
            self.left = Node(val)
            self.left_count += 1
        elif self.right is None:
            self.right = Node(val)
            self.right_count += 1
        elif self.left_count > self.right_count + self.needed_to_even or not self.even_depth:
            self.even_depth = False
            if self.left_count == self.right_count:
                self.needed_to_even *= 2
                self.even_depth = True
            self.right.insert(val)
            self.right_count += 1
        else:
            self.left.insert(val)
            self.left_count += 1

【讨论】:

    【解决方案2】:

    您的树完全按照您的代码建议构建。

    insert 函数检查是否有一个空子节点,如果找到则设置 - 否则它会递归地向左移动(不管它的长度),而这正是你得到的树。

    第二,你的输出不清楚——你加None是什么意思?

    为了实现完整树的构建,您需要对元素进行计数。

    然后我们将能够使用计数除以 2 来找到正确的路径(走叶或右)直到到达右叶。将self.cnt = 1 添加到构造函数中。将其用于插入的伪代码:

    insert:
        cnt = self.cnt++ // Increase the count and get the new value
        while (cnt > 0) {
            path.push(cnt % 2 == 0 ? left : right) // If even, go left. Else go right.
            cnt = cnt / 2
        }
        path.reverse // We need to start from the last element we pushed
        current = head
        while (path not empty)
            current = current.path.pop
        current = val
    

    尝试查看树号以更好地理解它:

                 1
               /   \
              2     3
             / \   /  \
            5   6 7    8
    

    【讨论】:

      【解决方案3】:

      您的代码将在找到不是 None 的节点后立即向左遍历,这就像 depth-first search (DFS)。所以代码没有再往右边看,看看那里是否还有一些空缺要填补,但无论如何都会向左走。这会导致您的树偏向左侧。

      相反,您应该使用breadth-first search (BFS) 来搜索树中的下一个空缺,所以在 breadth 第一顺序。为此,您可以使用单独的方法来执行此 BFS 并返回空缺的位置(通过提供其父节点以及新的子节点应该在哪一侧)。

      这是新方法的外观:

      def next_free(self):
          queue = [self]
          while len(queue):
              node = queue.pop(0) # Here you get the nodes in BFS order
              if node.val is None: # Cannot have children
                  continue
              for side, child in enumerate((node.left, node.right)):
                  if child is None: # Found the first vacancy in BFS order!
                      return node, side
                  queue.append(child)
      

      现在insert 方法变得微不足道了:

      def insert(self,val):
          node, side = self.next_free()
          if side == 0:
              node.left = Node(val)
          else:
              node.right = Node(val)
      

      你可以看到它在repl.it上运行。

      【讨论】:

      • 关于BTree,在同一天(UTC 日,2019-08-08T1833,由 OP)进行了重命名,BTree → BinTree。您可能想更新您的答案。
      猜你喜欢
      • 1970-01-01
      • 2020-02-28
      • 2011-07-14
      • 1970-01-01
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 2016-01-17
      • 1970-01-01
      相关资源
      最近更新 更多