【问题标题】:Traversing a binary tree in Python在 Python 中遍历二叉树
【发布时间】:2017-05-20 03:05:41
【问题描述】:

我几乎完成了一个项目,该项目让我们创建一个使用二叉树结构的字典类。然而,我被困在如何实现一个打印出树中所有元素的方法上,我只是没有太多的二叉树经验,所以在如何编码上相当混乱。

我试图找出的方法是一个键方法,它将遍历整个树并返回所有键的列表。我认识的人暗示我应该创建一个私有帮助函数,递归遍历树并跟踪所有键。我想创造他在说什么,但我不知道如何编码。任何人都可以帮我编码吗?弄清楚这一点几乎可以为我完成所有工作。

到目前为止,这是我的代码。 [Key:Value] 对是元组。我已经对其进行了编码,并且还从教科书示例中获得了一些帮助来构建您在此处看到的所有内容:

class DictWithTree:

    def __init__(self):
        self._element = None
        self._left = None
        self._right = None
        self._size = 0

    def isempty(self):
        if self._element == None:
            return True
        return False

    def __len__(self):
        return self._size

    def __contains__(self,key):
        path = self._tracePath(key)
        return path[-1]._size > 0

    def _tracePath(self,key): # taken from the textbook example and modified
        if len(self) == 0 or key == self._element[0]:
            return [self]   
        elif len(key) < len(self._element[0]):
            return [self] + self._left._tracePath(key)
        else:
            return [self] + self._right._tracePath(key)

    def __getitem__(self,key):
        if len(self) == 0:
            raise KeyError(key)   
        elif key == self._element[0]:
            return self._element[1]
        elif key < self._element[0]:
            return self._left[key]
        elif key > self._element[0]:
            return self._right[key]
        else:
            raise KeyError(key)

    def __setitem__(self,key,value):
        path = self._tracePath(key)
        endOfPath = path[-1]
        if endOfPath._element != None:       
            if endOfPath._element[0] == key: 
                endOfPath._element = key,value
        if endOfPath._size == 0: # a new element
            for location in path:
                location._size += 1
            endOfPath._element = key,value
            endOfPath._left = DictWithTree()
            endOfPath._right = DictWithTree()

    def clear(self):
        self._element = None
        self._left = None
        self._right = None
        self._size = 0

    def pop(self,key):
        value = self[key]
        self._remove(key)
        return value

    def popitem(self):     # returns the 'last' item in the dictionary,
        if self.isempty(): # (i.e. the largest key in the dictionary)
            return KeyError("There are no keys in the dictionary")
        elif self._right._element == None:
            return self._element
        else:   
            return self._right.popitem()                                   

    def _remove(self,key):
        path = self._tracePath(key)
        endOfPath = path[-1]
        if endOfPath._size > 0:
            for location in path:
                location._size -= 1
            if len(endOfPath._left) == 0:
                endOfPath._promoteChild(endOfPath._right)
            elif len(endOfPath._right) == 0:
                endOfPath._promoteChild(endOfPath._left)
            else:
                endOfPath._element = endOfPath._left.pop()

    def _promoteChild(self,child):
        self._element = child._element
        self._left = child._left
        self._right = child._right

【问题讨论】:

  • 为什么要使用自己编写的树而不是 Python 字典?
  • 这是一个项目,这是我们应该做的。创建一个使用二叉树的字典。
  • 我相信他说过这就是他的项目规范。
  • 如果有人可以提供帮助,那将是天赐之物。我还必须实现其他方法,但它们都源自完成此键方法。可能只有 10-12 行代码阻止我完成:D
  • @Eric 您应该接受这些答案之一,或者如果这些答案都不是您需要的,则发布您的最终解决方案......当然,我假设您完成了您的项目?

标签: python binary-tree


【解决方案1】:

你需要做的就是创建一个辅助方法visitAllSubnodes(node),它对当前节点做一些事情,然后递归地在左右子节点上调用它自己。 visitAllSubnodes(node) 所做的可以是任何东西,在您的情况下,它可能类似于 print(node._element),但您可以使您的功能非常模块化,例如

def visitAllSubnodes(node, whatToDoAtEachNode):
    whatToDoAtEachNode(node)
    visitAllSubnodes(node._left, whatToDoAtEachNode)
    visitAllSubnodes(node._right, whatToDoAtEachNode)

def printAllElements(node):
    visitAllSubnodes(node, lambda x:print(x))

要真正返回一些东西,你需要使用高阶函数和闭包的概念。例如,您可以创建一个定义私有个人累加器(您添加到的列表)的函数,以及该私有个人累加器所属的另一个函数,然后返回该函数。

因此,例如,每次遍历树时,您都可以调用这个高阶函数,我们称之为makeFunctionWhichKeepsTrackOfWhatHasBeenPassedIntoIt(),它返回一个函数,该函数跟踪传递给它的内容以及累加器。我会提供更多信息,但这将是问题集的重点。 =)

【讨论】:

    【解决方案2】:

    还有另一种使用 Python 3 的yield from 进行递归有序树遍历的解决方案:

    def traverse(tree):
        if tree.left is not None:
            yield from traverse(tree.left)
    
        yield tree.value
    
        if tree.right is not None:
            yield from traverse(tree.right)
    
    print(list(traverse(tree_root)))
    

    我认为它更具可读性和概念上的简单。我希望它会对某人有所帮助。

    【讨论】:

      【解决方案3】:

      应该这样做

      def allKeys(d):
          toVisit = []
          toVisit.append(d)
          while (len(toVisit)>0):
              x = toVisit.pop()
              if x._element:
                  yield x._element[0]
              if x._left:
                  toVisit.append(x._left)
              if x._right:
                  toVisit.append(x._right)
      

      对于有序遍历,您需要一个递归求解,如维基百科entry 中关于树遍历的内容。

      【讨论】:

      • 说你想让它返回一个包含所有键的列表,我该怎么做?我之前也从未使用过“yield”或使用过生成器。现在,它只是打印出“
      • NM 关于最后一条评论,我已经开始工作了。但是,我能做些什么让它按顺序打印吗?它似乎做了以下事情:Root ---> Keys Larger than Root ---> Keys Smaller than Root
      【解决方案4】:

      对于树的遍历,通常人们会进行广度优先遍历 (BFT) 或深度优先遍历 (DFT)。

      在 BFT 中,您使用队列来记住您离开的地方,在 DFT 中,您使用堆栈来记住您离开的地方。如果你知道队列和栈的本质,理解BFT和DFT只是小菜一碟,否则请阅读Breadth-first searchDepth-first search,顺便提一下,遍历树的代码通常不超过10行证明它们是多么容易。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-01
        • 2022-11-11
        • 1970-01-01
        • 2010-12-30
        • 2017-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多