二叉树的递归遍历
这里主要是了解一下二叉树的结构还有递归遍历的三种方法,我对二叉树有基础所以我打算直接看一下卡哥的视频查漏补缺一下然后再把三种遍历在leetcode上面写完
前序遍历:
这里就是前序遍历的代码,是leetcode上的题,根据leetcode的要求我们需要返回一个按照前序遍历顺序记录每个node的val的数组,所以我新定义了一个function然后出了root这个param以外还有一个list
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def preorder_dfs(root, ls):
if not root:
return
ls.append(root.val)
preorder_dfs(root.left, ls)
preorder_dfs(root.right, ls)
preorder_dfs(root, res)
return res
后序遍历:
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
def postorder_dfs(root, ls):
if not root:
return
postorder_dfs(root.left, ls)
postorder_dfs(root.right, ls)
ls.append(root.val)
postorder_dfs(root, res)
return res
中序遍历:
好吧做到这里我发现之前写过的中序遍历的代码,我们一开始在leetcode给的function中声明了res list之后可以直接在内部函数中用的,不需要再新加一个param
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# create the result list
res = []
# define the depth first search with in order traversal
def dfs(root):
if not root:
return
dfs(root.left)
res.append(root.val)
dfs(root.right)
dfs(root)
return res
二叉树的迭代遍历
听完了卡哥的讲解发现还是收获了很多,这里我们用迭代法的核心思想就是和递归一样利用栈这个数据结构还储存我们遍历每一个节点的顺序
前序遍历:
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
# create the stack to store node need to be checked
s = []
s.append(root)
# loop until stack is empty
while s:
node = s.pop()
if node:
res.append(node.val)
# add the left node and right node in the stack
s.append(node.right)
s.append(node.left)
return res
这里我们新建一个stack用来存放要遍历的node,在循坏开始之前我们先把root放进stack,然后呢我们开始循环,因为stack里面存的是我们要遍历的node,所以循环的条件就是当s空了之后,我们就找到了所有的node
然后呢我们直接就pop掉stack中的元素,因为这是中序遍历,所以我们检查完node是否存在以后,就直接把他的val加入到res中去,然后再重新把node的左右节点加入stack等待下一轮的遍历,这里因为stack采用后进先出,所以如果我们想要让我们的前序遍历遵循root->left->right 的顺序,我们要先把root.right 加入stack,后把root.left 加入
后序遍历:
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
res = []
# create the stack to store node need to be checked
s = []
s.append(root)
# loop until stack is empty
while s:
node = s.pop()
if node:
res.append(node.val)
# add the left node and right node in the stack
s.append(node.left)
s.append(node.right)
return res[::-1]
这里的后序遍历其实是利用了前序遍历的思路和两者的区别,我们可以发现对于前序遍历,顺序是root->left->right, 后序遍历的是left->right->root, 也就是说如果我们修改前序遍历中的找到node之后加入左右节点的熟悉就可以把前序遍历变成root->right->left 然后呢再翻转得到的数组其实就会变成left->right->root,也就是后序遍历了
中序遍历:
这里的中序遍历有一点区别,主要原因是我们对于节点的处理和我们遍历的顺序不一样了。所以我们需要额外再用一个pointer来遍历,然和呢stack依然是用来存放需要处理的节点
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
# create the result list and pointer
res = []
# create stack and pointer
cur = root
s = [root]
# as long as there is nodes left in stack, keep running
while s:
# go to the most left of the cur node first and add them to the stack
while cur:
cur = cur.left
s.append(cur)
# once we reach the most left, pop it and add it to the res
node = s.pop()
if node:
res.append(node.val)
# add the right node to the stack last and make cur point to it
# in case we have more left node from it
cur = node.right
s.append(cur)
return res
我们利用cur先从头然后一直向左遍历,在这个过程中优先把每一个root的左节点一一安排到stack中去,来保证后面当我们一个一个root处理完之后能立马回到最近的一个未处理的左节点上,当我们找到了最左边之后就可以处理了,直接pop出来然后把val加入到res里面,然后呢再把cur重新调到他的右节点上面,因为我们还要一直反复确定我们每一个遍历的节点需不需要继续去先找左节点加入stack,所以大的while loop中每一次开始我们都while cur, cur=cur.left,只有确定了这个右节点没有left了,我们就会再进行pop然后处理右节点加入res,这样周而复始就能中序遍历整个二叉树了
二叉树统一迭代遍历
这里二刷再细看吧,现在感觉研究统一迭代意义不大