文章目录

  • 二叉树的遍历
    • 前序遍历
      • 递归
      • 迭代 - 栈
    • 中序遍历
      • 递归
      • 迭代 - 栈
      • 莫里斯遍历
    • 后序遍历
      • 递归
      • 迭代 - 栈
    • 层序遍历
      • BFS-广度优先搜索 - 队列
      • 层序遍历-BFS
  • N叉树的遍历
    • N叉树的前序遍历
      • 递归
      • 迭代-栈
    • N叉树后序遍历
      • 递归
      • 迭代-栈
    • N叉树的层序遍历
      • BFS
  • 参考链接

二叉树的遍历

前序遍历

根 →\to→ 左 →\to→ 右

递归

#class TreeNode:
#   def __init__(self, x):
#       self.val = x
#       self.left = None
#       self.right = Nonedef preorderTraverersal(self, root:TreeNode) ->  List[int]:res = []def dfs(root):if not root:return res.append(root.val)  dfs(root.left)dfs(root.right)dfs(root)return res

迭代 - 栈

  • 初始化栈, 并将根节点入栈
  • 当栈不为空时,并将根节点入栈
    • 弹出栈顶元素node,并将值添加到结果
    • 如果node的右子树非空,将右子树入栈
    • 如果node的左子树非空,将左子树入栈

图来自参考链接-1

def preorderTraversal(self, root: TreeNode) -> List[int]:res = []if not root:return resstack = [root]while stack:node = stack.pop()res.append(node.val)  # 根节点加入结果if node.right:stack.append(node.right)if node.left:stack.append(node.left)return res

中序遍历

左 →\to→ 根 →\to→ 右

递归

# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = rightdef inorderTraversal(self, root: TreeNode) -> List[int]:res = []def dfs(root):if not root:return dfs(root.left)res.append(root.val)dfs(root.right)dfs(root)return res

迭代 - 栈

图来自参考链接-3

def inorderTraversal(self, root: TreeNode) -> List[int]:res = []if not root:return resstack = []cur = rootwhile stack or cur:while cur:      # cur入栈,并到达最左端的叶子节点stack.append(cur)cur = cur.lefttemp = stack.pop()res.append(temp.val)  # 出栈时再加入结果cur = temp.rightreturn res

莫里斯遍历

递归迭代的方式都使用了辅助的空间,而莫里斯遍历的优点是没有使用任何辅助空间。
缺点是改变了整个树的结构,强行把一棵二叉树改成一段链表结构。

图来自参考链接-3

将黄色区域部分挂到节点5的右子树上,接着再把25这两个节点挂到4节点的右边。这样整棵树基本上就变改成了一个链表了,之后再不断往右遍历

图来自参考链接-3

def inorderTraversal(self, root: TreeNode) -> List[int]:res = []cur = rootwhile cur:if not cur.left:# 左子树为空,则打印这个节点,并向右边遍历res.append(cur.val)cur = cur.rightelse:# 如果左节点不为空,就将当前节点连带右子树全部挂到左节点的最右子树下面pre = cur.leftwhile pre.right and pre.right != cur:pre = pre.rightif not pre.right:pre.right = curcur = cur.leftelse:pre.right = Noneres.append(cur.val)cur = cur.rightreturn res

后序遍历

左 →\to→ 右 →\to→ 根

递归

#class TreeNode:
#   def __init__(self, x):
#       self.val = x
#       self.left = None
#       self.right = Nonedef preorderTraverersal(self, root:TreeNode) ->  List[int]:res = []def dfs(root):if not root:return  dfs(root.left)dfs(root.right)res.append(root.val) dfs(root)return res

迭代 - 栈

  方法 一: 将迭代前序遍历的顺序,逆置过来,从前序根→\to→ 左 →\to→ 右变到后序 左 →\to→ 右 →\to→ 根,再在代码中改变左右的入栈顺序。

def postorderTraversal(self, root: TreeNode) -> List[int]:res = []if not root:return resstack = [root]while stack:node = stack.pop()if node.left:stack.append(node.left)if node.right:stack.append(node.right)res.append(node.val)return res[::-1]

  方法 二: 和上面中序遍历类似,改变而来,从到达左端改为到达最右端。

def postorderTraversal(self, root: TreeNode) -> List[int]:res = []if not root:return rescur = rootstack = [root]while stack:while cur:res.append(cur.val)stack.append(cur)cur = cur.righttemp = stack.pop()cur = temp.leftreturn res[::-1]

  方法 三:参考链接 5

后序遍历每个根节点都要经过三次:第一次遇到它时要立即转去处理其左子树,第二次从左子树经由它转去处理右子树,第三次从右子树回来才应该处理根节点数据,然后返回上一层。
  执行cur = root,方便遍历以免引起混淆。cur的值是当前节点(可能为空),在实现遍历的循环中维持一种不变的关系: ·

  • 栈中节点序列的左边是二叉树已经遍历过的部分,右边是尚未遍历的部分;
  • 如果cur不为空,其父节点就是栈顶节点;
  • cur为空时栈顶就是应该访问的节点。

  根据被访问节点是其父节点的的左节点或右节点就可决定下一步该怎么做:若是左节点就转到右节点;若是右节点就应该处理根节点并强制退栈。
  函数定义中外层循环内嵌套了一个内层循环,该内层循环的目标是找到下一个应访问的节点。
注意:

  • 内层循环找到当前子树的最下最左节点,将其入栈后终止;
  • 若被访问节点是其父节点的左子节点,应直接转到其右兄弟节点继续访问;
  • 若被处理节点是其父节点的右子节点,设cur = None将迫使外层循环的下次迭代弹出并访问更上一层的节点。
def postorderTraversal(self, root: TreeNode) -> List[int]:res = []  stack = []  cur = rootwhile stack or cur:while cur:stack.append(cur)  # 第一次入栈的是根节点# 判断当前节点的左子树是否存在,若存在则持续左下行,若不存在就转向右子树cur = cur.left if cur.left is not None else cur.right# 循环结束说明走到了叶子节点,没有左右子树了,该叶子节点即为当前栈顶元素,应该访问了cur = stack.pop() # 取出栈顶元素进行访问res.append(cur.val) # 将栈顶元素也即当前节点的值添加进res# (下面的stack[-1]是执行完上面那句取出栈顶元素后的栈顶元素)if stack and stack[-1].left == cur: #若栈不为空且当前节点是栈顶元素的左节点cur = stack[-1].right   ## 则转向遍历右节点else:cur = None  # 没有左子树或右子树,强迫退栈return res

  方法 四:标记法,参考链接 1 & 4

每次从栈中弹出元素时,如果 flag0,则需要将flag变为1 并连同该节点再次入栈,只有当 flag 为1时才可将该节点加入到结果中。

图来自参考链接-1

def postorderTraversal(self, root: TreeNode) -> List[int]:res = []if not root:return []stack = [(0, root)] while stack:flag, cur = stack.pop()if not cur:continueif flag == 0:# 后序stack.append((1, cur))stack.append((0, cur.right))stack.append((0, cur.left))# 前序# stack.append((0, cur.right))# stack.append((0, cur.left))# stack.append((1, cur))# 中序# stack.append((0, cur.right))# stack.append((1, cur))# stack.append((0, cur.left))else:   # flag == 1 已遍历过了res.append(cur.val)return res

层序遍历

BFS-广度优先搜索 - 队列

广度优先搜索的步骤为:

  • 初始化队列queue,并将根节点root加入到队列
  • 当队列不为空时
    • 队列中弹出节点node,加入到结果中
    • 如果左子树非空,左子树加入队列
    • 如果右子树非空,右子树加入队列

图来自参考链接-1

# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Nonedef levelOrder(self, root: TreeNode) -> List[List[int]]:res = []if not root:return []queue = [root]while queue:size = len(queue)  # 获取当前队列的长度,此长度相当于这一层节点的个数level = []     # 存储每一层的节点for i in range(size):node = queue.pop(0)     # 这里相当于一个队列level.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)res.append(level)return res

层序遍历-BFS

图来自参考链接-6 层序遍历 节点进队列和出队列的过程

图来自参考链接-6

N叉树的遍历

N叉树的前序遍历

递归

# class Node:
#    def __init__(self, val=None, children=None):
#        self.val = val
#        self.children = childrendef preorder(self, root: 'Node') -> List[int]:res = []def dfs(node):if not node:return res.append(node.val)for child in node.children:dfs(child)dfs(root)return res

迭代-栈

  使用一个来得到前序遍历,需要保证栈顶的节点就是我们当前遍历到的节点。首先把根节点入栈,因为根节点是前序遍历中的第一个节点。随后每次我们从栈顶取出一个节点u,它是我们当前遍历到的节点,并把 u的所有子节点逆序推入栈中。例如 u 的子节点从左到右为 v1, v2, v3,那么推入栈的顺序应当为 v3, v2, v1,这样就保证了下一个遍历到的节点(即u 的第一个子节点 v1)出现在栈顶的位置。

def preorder(self, root: 'Node') -> List[int]:res = []if root is None:return []stack = [root]while stack:node = stack.pop()res.append(node.val)stack.extend(node.children[::-1])return res

N叉树后序遍历

递归

"""
class Node:def __init__(self, val=None, children=None):self.val = valself.children = children
"""def postorder(self, root: 'Node') -> List[int]:res = []def dfs(root):if not root:return node = root.childrenfor child in node:dfs(child)res.append(root.val)dfs(root)return res

迭代-栈

  在后序遍历中,会先遍历一个节点的所有子节点,再遍历这个节点本身。例如当前的节点为u,它的子节点为 v1, v2, v3时,那么后序遍历的结果为[children of v1], v1, [children of v2], v2, [children of v3], v3, u,其中 [children of vk] 表示以 vk 为根节点的子树的后序遍历结果(不包括 vk本身)。将这个结果反转,可以得到 u, v3, [children of v3]’, v2, [children of v2]’,v1, [children of v1]’,其中 [a]' 表示 [a]的反转。此时发现,结果和前序遍历非常类似,只不过前序遍历中对子节点的遍历顺序是v1, v2, v3,而这里是 v3, v2, v1
  因此可以使用和 N叉树的前序遍历相同的方法,使用一个栈来得到后序遍历。首先把 根节点入栈。当每次从栈顶取出一个节点 u时,就把u的 所有子节点顺序推入栈中。例如 u的子节点从左到右为 v1, v2, v3,那么推入栈的顺序应当为 v1, v2, v3,这样就保证了下一个遍历到的节点(即 u的第一个子节点 v3)出现在栈顶的位置。在遍历结束之后,把 遍历结果反转,就可以得到后序遍历。

def postorder(self, root: 'Node') -> List[int]:res = []if not root:return Nonestack = [root]while stack:node = stack.pop()res.append(node.val)children = node.childrenfor child in children:stack.append(child)return res[::-1]

N叉树的层序遍历

BFS

"""
class Node:def __init__(self, val=None, children=None):self.val = valself.children = children
"""
def levelOrder(self, root: 'Node') -> List[List[int]]:res = []if not root:return []def bfs(root):queue = [root]while queue:nxt = []   # 下一轮 while提供新数据temp = []   # 本轮结果for node in queue: temp.append(node.val)for child in node.children:nxt.append(child)res.append(temp)queue = nxt   # 赋值新收集到的节点bfs(root)return res

  简写此过程

def levelOrder(self, root: 'Node') -> List[List[int]]:res = []if not root:return []queue = [root]while queue:res.append([node.val for node in queue])queue = [child for node in queue for child in node.children if child]return res

在搜索的同时加上层次信息,根据层次信息判断当前搜索结点的所属子列表。

def levelOrder(self, root: 'Node') -> List[List[int]]:res = []if not root:return []queue = [(0,root)]                        #初始化while queue:level,node = queue.pop(0)if len(res) == level:                   #判断当前结点的层次信息res.append([node.val])else:res[level].append(node.val)if node.children:                       #将当前结点的子节点全部加到队列中for i in node.children:queue.append((level+1,i))return res

参考链接

1-参考链接-LeetCode题解-图解二叉树的四种遍历
2-参考链接-LeetCode题解
3-参考链接-LeetCode题解-动画演示+三种实现
4-参考链接-LeetCode题解-全解模板
5-参考链接-LeetCode题解-后序遍历
6-参考链接-LeetCode题解-BFS使用场景总结
7-参考链接-LeetCode题解-N叉树前序遍历官方题解
8-参考链接-LeetCode题解-N叉树后序遍历官方题解
9-参考链接-LeetCode题解-N叉树层序遍历-DFS+BFS
10-参考链接-LeetCode题解-N叉树层序遍历-BFS
11-参考链接-LeetCode题解-N叉树层序遍历官方题解

Python 树的遍历相关推荐

  1. python作者 google面试_如果Google面试让你用python写一个树的遍历程序

    前几天忽然对python很感兴趣,学了几天也感觉它非常的简洁实用.打破了我这么长时间对java C# C 和vb的审美疲劳,让我眼前一亮."就像读英文一样简单"这句话评价pytho ...

  2. python实现树的遍历

    二叉树的遍历是指按照某种顺序依次访问树中的所有节点一次. 四种遍历方式分别是:先序遍历.中序遍历.后序遍历.层序遍历.其中前三种属于深度优先遍历(DFS),后一种属于广度优先遍历(BFS). 首先声明 ...

  3. 树的遍历(python)

    树的遍历Tree Traversals ❖对一个数据集中的所有数据项进行访问的操作称为"遍历Traversal" ❖线性数据结构中,对其所有数据项的访问比较简单直接按照顺序依次进行 ...

  4. python实现二叉树遍历(前序遍历、中序遍历、后序遍历)

    python实现二叉树遍历(前序遍历.中序遍历.后序遍历) 在计算机科学中,二叉树是一种树数据结构,其中每个节点最多有两个子节点,称为左子节点和右子节点.使用集合理论概念的递归定义是(非空)二叉树是元 ...

  5. LeetCode 589. N-ary Tree Preorder Traversal-多子节点树前序遍历--递归,迭代--反向压栈--C++解法

    LeetCode 589. N-ary Tree Preorder Traversal-多子节点树前序遍历–递归,迭代–反向压栈–C++解法 LeetCode题解专栏:LeetCode题解 LeetC ...

  6. Python实现深度优先遍历和广度优先遍历

    转载自:http://blog.csdn.net/bone_ace/article/details/46718683 python实现二叉树和它的七种遍历 介绍 树是数据结构中非常重要的一种,主要的用 ...

  7. 树的遍历(中序,前序,后序)

    与只有一种逻辑遍历它们的线性数据结构(数组.链表.队列.堆栈等)不同,树可以以不同的方式遍历,常见的有中序遍历,前序遍历和后序遍历. 实现各种遍历的方法又包括: 以上图为例: 深度优先遍历:  (a) ...

  8. mysql 遍历_MySQL 实现树的遍历详解及简单实现示例

    MySQL 实现树的遍历 经常在一个表中有父子关系的两个字段,比如empno与manager,这种结构中需要用到树的遍历.在Oracle 中可以使用connect by简单解决问题,但MySQL 5. ...

  9. 那些妖术——树的遍历

    本文参加CSDN博客大赛,如果你喜欢请投一票,非常感谢! 这个方法有点邪门,和大家在课堂上学的有点不一样,所以blog的名字取得有点邪乎. 一般的程序员应聘技术类的笔试都会有一道题目,那就是树的遍历( ...

最新文章

  1. linux 股票指南针,linux 基础命令 1
  2. Windows 系统下设置Nodejs NPM全局路径
  3. django手机访问_在手机上运行Python的神器
  4. Sybase中字符串替换函数 STR REPLACE
  5. dart系列之:手写Library,Library编写实践
  6. ASP.NET中的Eval()和DataBinder.Eval()方法
  7. python装饰器由浅入深_由浅入深理解Python装饰器
  8. linux 网卡 巨帧,Linux Kernel e1000e驱动巨型帧处理绕过安全检查漏洞
  9. Linux编译C没有文件名,crt1.o linux x64上没有这样的文件c编译错误
  10. 封头名义厚度如何圆整_松原封头价格
  11. 2017甘肃省计算机二级考试,甘肃省2017年计算机二级考试网上报名须知及流程
  12. SpringBoot解决jpa,NoSession问题
  13. 修改ORACLE RAC的字符集(记录一下)
  14. C语言函数程序实例(超全)
  15. js split 正则分割字符串
  16. ant design vue 描述列表Descriptions数据绑定
  17. 微信分享功能(weixin-js-sdk)
  18. 一阶导数和二阶导数的一些性质
  19. zabbix_proxy代理服务器搭建教程
  20. 四、入门python第四课

热门文章

  1. 小蚁宋烨:为什么要和小米合作?
  2. Multimodal-intersection-analysis-MIA-/ github
  3. 超越 Xshell!号称下一代终端神器,用完爱不释手!
  4. 数据结构与算法(b站老甲鱼)
  5. 基于单片机病房呼叫系统数码管显示房号设计-基于单片机工业生产现场的光照强度控制设计-基于单片机多功能智能台灯设计-基于单片机二维码LCD显示设计-基于单片机多功能时钟闹钟万年历控制系统设计【毕设分享】
  6. 对世界保持一份好奇心,或将改变你平淡的一生
  7. 我给航母做3D还原:这三处细节,太震撼了…
  8. ipad itunes 恢复
  9. 写在公众号之前——QT,ARM,DSP,单片机,电力电子与传动!
  10. vss报错Workgroup无法访问,您可能没有权限使用网络资源解决办法