摘要:前序输出从这一路下来,有两个是正确的,如果先判断要遍历的节点是否已经遍历过的话,那么就走不通了,所以应该允许,点到就记一次输出,再来判断是否能继续往下走。
代码来自:pickle and cPickle – Python object serialization
首先树的结构,如图
import pickle class Node(object): """A simple digraph where each node knows about the other nodes it leads to. """ def __init__(self, name): self.name = name self.connections = [] return def add_edge(self, node): "Create an edge between this node and the other." self.connections.append(node) return def __iter__(self): return iter(self.connections) def preorder_traversal(root, seen=None, parent=None): """Generator function to yield the edges via a preorder traversal.""" if seen is None: seen = set() yield (parent, root) if root in seen: return seen.add(root) for node in root: for (parent, subnode) in preorder_traversal(node, seen, root): yield (parent, subnode) return def show_edges(root): "Print all of the edges in the graph." for parent, child in preorder_traversal(root): if not parent: continue print "%5s -> %2s (%s)" % (parent.name, child.name, id(child)) # Set up the nodes. root = Node("root") a = Node("a") b = Node("b") c = Node("c") # Add edges between them. root.add_edge(a) root.add_edge(b) a.add_edge(b) b.add_edge(a) b.add_edge(c) a.add_edge(a) print "ORIGINAL GRAPH:" show_edges(root) # Pickle and unpickle the graph to create # a new set of nodes. dumped = pickle.dumps(root) reloaded = pickle.loads(dumped) print print "RELOADED GRAPH:" show_edges(reloaded)
输出结果:
$ python pickle_cycle.py ORIGINAL GRAPH: root -> a (4299721744) a -> b (4299721808) b -> a (4299721744) b -> c (4299721872) a -> a (4299721744) root -> b (4299721808) RELOADED GRAPH: root -> a (4299722000) a -> b (4299722064) b -> a (4299722000) b -> c (4299722128) a -> a (4299722000) root -> b (4299722064)
其中preorder_traversal是生成器。这里记录下生成器方法的每一步的意思。
# root 要遍历的根节点 # seen 保存遍历过的节点(集合) # parent 每次yield的父节点,有可能不存在 def preorder_traversal(root, seen=None, parent=None): """Generator function to yield the edges via a preorder traversal.""" if seen is None: # 如果没有开始遍历,seen是空,初始化集合 seen = set() yield (parent, root) # 记一次输出,这个要在下面判断之前 if root in seen: # 要遍历的根节点是否已经遍历过,防止循环遍历 return seen.add(root) # 保存已遍历的“根”节点 for node in root: # 遍历子节点 for (parent, subnode) in preorder_traversal(node, seen, root): yield (parent, subnode) return
一开始不明白的地方是这样
yield (parent, root) # 记一次输出,这个要在下面判断之前 if root in seen: # 要遍历的根节点是否已经遍历过,防止循环遍历 return
为什么不是先判断呢。
看循环引用的情况。
前序输出从root -> a -> b -> a这一路下来,有两个a是正确的,
如果先判断要遍历的节点是否已经遍历过的话,那么
b -> a就走不通了,所以应该允许,点到就记一次输出,再来判断是否能继续往下走。
b -> a记一次输出,接下来发现a已经遍历过它的子节点了(a in seen),才停止不往下遍历。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/37585.html
摘要:第一行为前序遍历,第二行为中序遍历。例如输入前序遍历序列和中序遍历序列,则重建二叉树并返回。根据前序遍历和中序遍历的结果可以拿到左子中序遍历和右侧为右子树中序遍历左子树的前序遍历和右子树的前序遍历然后递归左子树和右子树的完成重建。 二叉树简介 基本结构: function TreeNode(x) { this.val = x; this.left = null; ...
阅读 2216·2021-08-23 09:46
阅读 890·2019-08-29 18:31
阅读 1835·2019-08-29 17:04
阅读 2427·2019-08-29 12:23
阅读 1836·2019-08-26 14:05
阅读 1056·2019-08-26 13:44
阅读 3112·2019-08-26 12:23
阅读 2166·2019-08-26 10:46