版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明,违反必究。
本文链接:https://blog.csdn.net/junxing2018_wu/article/details/116713857
遍历通常分为**前序遍历、中序遍历、后序遍历、层序遍历**四种方式。
需要提一句的是,遍历方式只是打印顺序而已,四种遍历复杂度是相同。
- 前序遍历:根 - 左 - 右
- 中序遍历:左 - 根 - 右
- 后序遍历:左 - 右 - 根
- 层序遍历:根节点 - 第1层 - 第2层 - … 最后一层
非递归遍历(辅助栈)
由于每个节点都要进栈和出栈,所以时间复杂度为O(N),同样空间复杂度也为O(N),N为结点数。
-
前序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def preorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] pre = None res = [] stack = [root] while stack: temp = stack.pop() res.append(temp.val) # 因为栈先进后出,因此子节点压入的顺序是先右后左。 if temp.right: stack.append(temp.right) if temp.left: stack.append(temp.left) return res def preorderTraversal_0(self, root: TreeNode) -> List[int]: if root is None: return [] else: result = [root.val] stack = [root.right, root.left] while len(stack)>0: node = stack.pop() if node is not None: result.append(node.val) stack.extend([node.right, node.left]) return result def preorderTraversal_1(self, root: TreeNode) -> List[int]: node = root stack = [] ret = [] while (node or stack): # 树不空,或者堆栈不空 while node: # 只要节点不是 None,即树不空,就一直把节点压入堆栈,并且一直往左走到死胡同里,结束循环 stack.append(node) # 入栈(第一次碰到) ret.append(node.val) # 前序遍历是第一次碰到就输出 node = node.left # 一直往左走,并一直压入堆栈 # 上述压栈循环结束,跳出 if stack: node = stack.pop() # 出栈(第二次碰到,中序遍历就是放在这里之后),开始往回走,pop出 node node = node.right # 继续往右走 return ret
-
后序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def postorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] pre = None ret = [] stack = [root] while stack: temp = stack[-1] # 这里不能直接用pop,因为只有读取该节点的时候才要已经读取了的节点pop出栈 if (temp.left == None and temp.right == None) or (pre and (pre == temp.left or pre == temp.right)): # 用pre来进行标志,由于是后序遍历, # 如果当前节点是叶节点(左右子节点为空),读取值, # 如果不是叶节点但是pre是他的子节点, # 就说明这个节点也是当前应该读取的点 ret.append(temp.val) pre = temp stack.pop() else: # 因为栈先进后出,因此子节点压入的顺序是先右后左。 if temp.right: stack.append(temp.right) if temp.left: stack.append(temp.left) return ret def postorderTraversal_0(self, root: TreeNode) -> List[int]: if root is None: return [] else: result = [] stack = [root.val, root.right, root.left] while len(stack)>0: node = stack.pop() if isinstance(node, TreeNode): stack.extend([node.val, node.right, node.left]) elif isinstance(node, int): result.append(node) return result def postorderTraversal_1(self, root: TreeNode) -> List[int]: node = root stack = [] ret = [] while (node or stack): while node: stack.append(node) ret.append(node.val) node = node.right # 先 right,再 left if stack: node = stack.pop() node = node.left return ret[::-1] # 最后逆序输出 def postorderTraversal_2(self, root: TreeNode) -> List[int]: if root is None: return [] ret = [] stack = [] stack.append(root) while len(stack) > 0: node = stack.pop() left = node.left right = node.right ret.append(node.val) if left is not None: stack.append(left) if right is not None: stack.append(right) return ret[::-1]
-
中序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: """ 中序遍历 迭代 1. 遇到一个节点,将其压入堆栈,并去遍历它的左子树 2. 当左子树遍历结束后,从栈顶弹出这个节点并访问它 3. 然后按照其右指针再去中序遍历该节点的右子树 """ node = root stack = [] ret = [] while (node or stack): while node: stack.append(node) # 第一次碰到 node = node.left if stack: node = stack.pop() # pop 出 node,即第二次碰到 ret.append(node.val) # 第二次碰到之后输出 node = node.right return ret def inorderTraversal_0(self, root: TreeNode) -> List[int]: if root is None: return [] else: result = [] stack = [root.right, root.val, root.left] while len(stack)>0: node = stack.pop() if isinstance(node, TreeNode): stack.extend([node.right, node.val, node.left]) elif isinstance(node, int): result.append(node) return result
-
层序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def levelOrder(self, root: TreeNode) -> List[List[int]]: def children(root: TreeNode): return [n for n in [root.left, root.right] if n is not None] if root is None: return [] else: result = [] node_list = [root] while len(node_list) > 0: result.append([n.val for n in node_list]) tmp_stack = [] for n in node_list: tmp_stack += children(n) node_list = tmp_stack return result
递归遍历
递归实现的本质也是系统帮我们建立了栈结构,而系统栈需要记住每个节点的值,所以空间复杂度仍为O(N)
时间复杂度根据master公式求得。
公式 T(N) = a*T(N/b) + O (N^d)
代入公式得:T(N)=2*T(N/2)+O(1),即 a = 2, b = 2, d = 0
得到 log(2,2) = 1 > 0,
代入公式得:O(N^log(b,a)) = O(N^log(2,2)) = O(N)
所以递归遍历的时间复杂度为O(N)。
-
前序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def preorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] else: return ( [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right) )
-
后序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def postorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] else: return ( self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val] )
-
中序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] else: return ( self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right) )
莫里斯(Morris)遍历
时间复杂度为O(N),空间复杂度为O(1),N为结点数。
Morris遍历的实现原则
0 记作当前节点为cur。
1 如果cur无左孩子,cur向右移动(cur=cur.right)
2 如果cur有左孩子,找到cur左子树上最右的节点,记为mostright
a. 如果mostright的right指针指向空,让其指向cur,cur向左移动(cur=cur.left)
b. 如果mostright的right指针指向cur,让其指向空,cur向右移动(cur=cur.right)
3 cur为空时,停止遍历实现以上的原则,即实现了morris遍历。
-
前序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def preorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] else: cur = root ret = [] mostRight = None while cur is not None: # cur表示当前节点,mostRight表示cur的左孩子的最右节点 mostRight = cur.left if mostRight is not None: # cur有左孩子,找到cur左子树最右节点 while mostRight.right is not None and mostRight.right != cur: mostRight = mostRight.right # mostRight的右孩子指向空,让其指向cur,cur向左移动 if mostRight.right is None: mostRight.right = cur ret.append(cur.val) cur = cur.left continue else: # mostRight的右孩子指向cur,让其指向空,cur向右移动 mostRight.right = None else: ret.append(cur.val) cur = cur.right return ret
-
中序遍历
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def inorderTraversal(self, root: TreeNode) -> List[int]: if root is None: return [] else: cur = root ret = [] mostRight = None while cur is not None: # cur表示当前节点,mostRight表示cur的左孩子的最右节点 mostRight = cur.left if mostRight is not None: # cur有左孩子,找到cur左子树最右节点 while mostRight.right is not None and mostRight.right != cur: mostRight = mostRight.right # mostRight的右孩子指向空,让其指向cur,cur向左移动 if mostRight.right is None: mostRight.right = cur cur = cur.left continue else: # mostRight的右孩子指向cur,让其指向空,cur向右移动 mostRight.right = None ret.append(cur.val) cur = cur.right return ret