前中后序遍历 + 层次遍历+迭代器遍历
前序遍历:
result = [] st = [root] while st: node = st.pop(-1) if node.right: st.append(node.right) if node.left: st.append(node.left) result.append(node.val) return result
入门代码不多解释了,这种做法就是列表后面取出一个节点,然后访问根节点(这一步在前面所以叫前序),之后将右侧节点先放入列表内,在将左侧节点放入列表内(因为你每次都是拿后面的,所以后放的先访问)。
拒绝递归写法,这样写更容易进行扩展。
之后就可以很方便的补上中序和后序。
中序做法:
中序访问是左根右,所以先从左侧一直访问到底,然后将这些节点保存在一个list中,从后面开始逐一拿出来找右侧是否有节点,如果有的话,从这个节点继续左侧访问到底。
访问到底的做法就是在访问左,从后面拿出来每个节点就是在访问根,查找这些节点是否有右节点是访问右。
res = [] stack = [] while stack or root: # 不断往左子树方向走,每走一次就将当前节点保存到栈中 # 这是模拟递归的调用 if root: stack.append(root) root = root.left else: tmp = stack.pop() res.append(tmp.val) root = tmp.right return res
后续做法:
很好理解,后续访问是左右根。增加的时候先加入左再加入右,如123这个树,增加的时候bag中是[2,3],访问的时候pop先出来的是3所以加入的是3的左右孩子。直到把3这棵树都遍历完才会处理2.所以结果是[1,3,3的孩子们先右后左,2,2的孩子们先右后左] 。最后我们取反,那就是[2的孩子们先左后右,2,3的孩子们先左后右,3,1],就是我们想要的左右根的顺序了。
if not root: return [] bag = [root] result = [] while bag: node = bag.pop() result.append(node.val) if node.left: bag.append(node.left) if node.right: bag.append(node.right) return result[::-1]
层次遍历:
每一层循环用一个列表保存这些节点,在最后的时候加到一起。
class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: queue =[] cur = [root] while cur: que_val = [] next_node = [] for node in cur: if node: next_node.extend([node.left,node.right]) que_val.append(node.val) cur = next_node if que_val: queue.append(que_val) return queue
把上一层的节点都拿出来,把它的左右孩子都放在容器中,都放好后,把这个节点指向这个容器的第一个节点。怎么写都可。
class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: if not root: return [] bag = [root] res= [] while bag: tmp = [] val = [] for node in bag: if node.left: tmp.extend([node.left]) if node.right: tmp.extend([node.right]) val.append(node.val) bag = tmp res.append(val) return res
使用迭代器来遍历也是一种非常可以的方法。

通过这道题来理解一下迭代器yeild和yeild from在树结构中的应用。首先这个yeild和yeild from我的理解是这样的:
对于yeild来说,它可以使当前函数变成一个迭代器,每次执行到yeild a代表停止,并等待时机返回a值。所以如果你使用一个迭代器.send(None)也就是老版本的next,就会获得一次的值。所以在你for循环中不断用 i 获取这个迭代器的值的时候,每一轮都是执行到yeild a返回了一个a然后等待下一轮,这样来的。
对于yeild from来说是这样的,如果一个函数里套一个函数,里面都有yeild那么来来回回传递非常复杂,有时候你外层函数并不需要这样传递,你只需要和你内层保持一致就好了,内层yeild什么你就yeild什么所以使用了yeild from。
看这段代码:
class Solution: def findMode(self, root: TreeNode) -> List[int]: #迭代器版本 def inorder(node): if node: yield from inorder(node.left) yield node.val #每次刀yeild的时候就返回一个迭代值 yield from inorder(node.right)
这样一段代码已经很明显了,通过yield完成一个中序遍历的递归,上下的yield from代表我返回的东西在inorder里面找到yield为止,这样就完成了一个中序遍历了。后面通过一个for就可以逐个拿到每个节点,这样非常的方便。
那么对于这道题来说,拿到每个节点后还有一些操作顺便讲完,因为题中要求了空间的大小,所以这样做:设置 ans = [] cnt,max_cnt,last = 0,0,None
for v in inorder(root): if v == last: #如果v和上面的数字相同 cnt += 1 #重复元素计数+1 else: cnt = 1 #不同的话重新技术 if cnt > max_cnt: #如果cnt计数比最大值要大 ans = [v] #最多的元素v放在ans里 max_cnt = cnt #cnt更新一下最大值 elif cnt == max_cnt: #如果cnt和最大的值相等 ans.append(v) #说明这个元素也是最多的元素之一 加入到ans中 last = v return ans
cnt代表当前值得节点已经连续出现多少个了,第一个if else代表如果出现重复了就+1个,如果没重复那肯定是新节点了重新计数变成1个。
max_cnt代表最大的个数是多少,因为求的是众数,所以统计最大值。第二个if else则是如果当前的比最大值要大了,那更新一下最大值变成cnt,在把当前这个节点值放入ans中,它可是第一个众数节点的值。如果cnt的数量和max cnt相等代表了这个新的节点的值出现 次数和最大的一样多,同样是众数,那么也需要加入到ans中。
每次循环过后,last节点要标记这个数字,用来和下一个数字比较是否相同。

浙公网安备 33010602011771号