二叉树层次遍历算法 python_二叉树的遍历详解:前、中、后、层次遍历(Python实现)...

二叉树的遍历详解:前、中、后、层次遍历(Python实现)

二叉树是一种常见的数据结构,而它的常见遍历方法有前序遍历、中序遍历、后续遍历、层次遍历——掌握这几种遍历方法是很有必要的。

假设我们二叉树节点的定义如下——

# Definition for a binary tree node.

class TreeNode:

def __init__(self, x):

self.val = x

self.left = None

self.right = None

前序遍历

1. 深度优先遍历(递归实现)

我们先看前序遍历二叉树的过程——

访问根结点

前序遍历左子树

前序遍历右子树

很容易就可以看出这个过程是递归的,所以可以很方便使用递归实现前序遍历。

def preorderTraversal(root: TreeNode) -> List[int]:

res = []

dfs(root, res)

return res

def dfs(root: TreeNode, res: List[int]) -> None:

if not root: return

res.append(root.val)

dfs(root.left, res)

dfs(root.right, res)

python 特色的二叉树前序遍历递归实现

def preorderTraversal(root: TreeNode) -> List[int]:

if not root: return []

return [root.val] + preorderTraversal(root.left) + preorderTraversal(root.right)

2.深度优先遍历(迭代实现)

由于递归是隐式的使用了栈(函数栈),所以也可以直接使用栈来实现递归。

def preorderTraversal(root: TreeNode) -> List[int]:

if root is None: return []

res, stack = [], [root]

while stack:

node = stack.pop()

if not node: continue

res.append(node.val)

if node.right:

stack.append(node.right)

if node.left:

stack.append(node.left)

return res

3.(颜色)标记法

核心思想如下:

使用标记记录节点的状态,比如使用 flag,当 flag = True 表示该节点未被访问

如果遇到未被访问的节点,则令 flag = False,依次将右节点、左节点、自身入栈

如果遇到已访问过的节点,则将节点的值输出

而只需要调整左右节点的入栈顺序,就可以变为中序遍历和后序遍历了。

def preorderTraversal(root: TreeNode) -> List[int]:

res, stack = [], [(root, True)]

while stack:

node, flag = stack.pop()

if not node: continue

if flag:

stack.append((node.right, True))

stack.append((node.left, True))

stack.append((node, False))

else:

res.append(node.val)

return res

中序遍历

1.深度优先遍历(递归实现)

中序遍历二叉树的过程——

中序遍历左子树

访问根结点

中序遍历右子树

因此,很容易使用递归实现中序遍历。

def inorderTraversal(root: TreeNode) -> List[int]:

res = []

dfs(root, res)

return res

def dfs(root: TreeNode, res: List[int]) -> None:

if not root: return

dfs(root.left, res)

res.append(root.val)

dfs(root.right, res)

python 特色的二叉树中序遍历递归实现

def inorderTraversal(root: TreeNode) -> List[int]:

if not root: return []

return inorderTraversal(root.left) + [root.val] + inorderTraversal(root.right)

2.深度优先遍历(迭代实现)

由于递归是隐式的使用了栈(函数栈),所以也可以直接使用栈来实现递归。

def inorderTraversal(root: TreeNode) -> List[int]:

res, stack, cur = [], [], root

while stack or cur:

while cur:

stack.append(cur)

cur = cur.left

cur = stack.pop()

res.append(cur.val)

cur = cur.right

return res

3.(颜色)标记法

核心思想如下:

使用标记记录节点的状态,比如使用 flag,当 flag = True 表示该节点未被访问

如果遇到未被访问的节点,则令 flag = False,依次将右节点、自身、左节点入栈

如果遇到已访问过的节点,则将节点的值输出

与前序遍历相比,仅改变了左节点和当前节点的入栈顺序。

def inorderTraversal(root: TreeNode) -> List[int]:

res, stack = [], [(root, True)]

while stack:

node, flag = stack.pop()

if not node: continue

if flag:

stack.append((node.right, True))

stack.append((node, False))

stack.append((node.left, True))

else:

res.append(node.val)

return res

后序遍历

1.深度优先遍历(递归实现)

后序遍历二叉树的过程——

后序遍历左子树

后序遍历右子树

访问根结点

因此,很容易使用递归实现后序遍历。

def postorderTraversal(root: TreeNode) -> List[int]:

res = []

dfs(root, res)

return res

def dfs(root: TreeNode, res: List[int]) -> None:

if not root: return

dfs(root.left, res)

dfs(root.right, res)

res.append(root.val)

python 特色的二叉树后序遍历递归实现

def postorderTraversal(root: TreeNode) -> List[int]:

if not root: return []

return postorderTraversal(root.left) + postorderTraversal(root.right) + [root.val]

2.深度优先遍历(迭代实现)

def postorderTraversal(root: TreeNode) -> List[int]:

if root is None: return []

res, stack = [], [root]

while stack:

node = stack.pop()

if not node: continue

res.append(node.val)

if node.left:

stack.append(node.left)

if node.right:

stack.append(node.right)

return res[::-1]

3.(颜色)标记法

核心思想如下:

使用标记记录节点的状态,比如使用 flag,当 flag = True 表示该节点未被访问

如果遇到未被访问的节点,则令 flag = False,依次将自身、右节点、左节点入栈

如果遇到已访问过的节点,则将节点的值输出

def postorderTraversal(root: TreeNode) -> List[int]:

res, stack = [], [(root, True)]

while stack:

node, flag = stack.pop()

if not node: continue

if flag:

stack.append((node, False))

stack.append((node.right, True))

stack.append((node.left, True))

else:

res.append(node.val)

return res

层次遍历

1.深度优先遍历(递归实现)

层次遍历相对于前中后序遍历而言,加多节点所在二叉树层数的信息。所以只需要添加一个变量 level 记录层数即可。

def levelOrder(root: TreeNode) -> List[List[int]]:

res = []

dfs(root, 0)

return res

def dfs(root: TreeNode, level: int) -> None:

if not root: return

if len(res) <= level:

res.append([])

res[level].append(root.val)

dfs(root.left, level+1)

dfs(root.right, level+1)

2.深度优先遍历(迭代实现)

由于递归是隐式的使用了栈(函数栈),所以也可以直接使用栈来实现递归。

我们不妨使用一个二元组 (node, level) 来表示状态。

def levelOrder(root: TreeNode) -> List[int]:

res, stack = [], [(root, 0)]

while stack:

node, level = stack.pop()

if not node: continue

if len(res) <= level:

res.append([])

res[level].append(node.val)

if node.right:

stack.append(node.right)

if node.left:

stack.append(node.left)

return res

3.(颜色)标记法

相对于前序遍历的标记法,层次遍历的标记法也仅仅添加了节点层数(level)的变量。

def levelOrder(root: TreeNode) -> List[int]:

res, stack = [], [(root, True, 0)]

while stack:

node, flag, level = stack.pop()

if not node: continue

if flag:

stack.append((node.right, True, level+1))

stack.append((node.left, True, level+1))

stack.append((node, False))

else:

if len(res) <= level:

res.append([])

res[level].append(node.val)

return res

4.广度优先遍历(队列实现)

因为层次遍历是逐层遍历的,所以可以使用广度优先遍历。

使用队列实现广度优先遍历,具体实现方法如下——

首先根节点入队

当队列不为空的时候

当前队列长度 si (当前队列长度即为当前层的节点数)

依次从队列中取出 si 元素,将其左右节点入队,进行下一次迭代

def levelOrder(root: TreeNode) -> List[int]:

if not root: return []

res, queue = [], [root]

while queue:

level_node = []

for _ in range(len(queue)):

node = queue.pop(0)

level_node.append(node.val)

if node.left:

queue.append(node.left)

if node.right:

queue.append(node.right)

res.append(level_node)

return res

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335045.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java终结器_Java的终结器仍然存在

java终结器当我第一次学习Java并从C 过渡到Java时&#xff0c;我记得我经常被告知&#xff0c;经常读到它不应该像C 析构函数那样对待Java终结器&#xff0c;也不应该依靠它。 该建议的频率和坚持性对我产生了影响&#xff0c;以至于我无法回忆起我上一次编写finalize&#xff…

Sublime Text如何安装和卸载插件

文章目录如何查找插件如何安装插件通过包控制器安装插件手动安装插件如何卸载插件如何查找插件 建议先通过插件库来搜索你想要的插件&#xff0c;找到你想要的插件之后&#xff0c;你再选择安装方式进行安装&#xff0c;搜索插件请点击以下链接&#xff1a; Package Control中…

@insert 对象_python中列表插入append(), extend(), insert()

1 append()append&#xff1a;只能接收一个参数&#xff0c;并且只能添加在列表的最后。添加数字 In [1]: a [1,2,3] In [2]: a.append(4) In [3]: a Out[3]: [1, 2, 3, 4] 添加字符串 In [6]: a [1,2,3] In [7]: a.append("daniel") In [8]: a Out[8]: [1, 2, 3, …

mysql的锁是公平的么_lock 默认公平锁还是非公平锁?公平锁是如何定义?如何实现...

ReentrantLock的实现是基于其内部类FairSync(公平锁)和NonFairSync(非公平锁)实现的。 其可重入性是基于Thread.currentThread()实现的: 如果当前线程已经获得了执行序列中的锁&#xff0c; 那执行序列之后的所有方法都可以获得这个锁。公平锁&#xff1a;公平和非公平锁的队列…

企业性质

有限责任公司(国有控股) 有限责任公司(自然人投资或控股) 其他有限责任公司 有限责任公司(外国法人独资) 股份有限公司(非上市、国有控股) 有限合伙企业 有限责任公司(非自然人投资或控股的法人独资) 有限责任公司(外国法人独资) 有限责任公司(国有独资) 有限责任公司(台港澳法…

常用jdk的命令行工具:_jhsdb:JDK 9的新工具

常用jdk的命令行工具:我喜欢在分析性能和基于Java的应用程序的其他问题的早期步骤中使用JDK随附的命令行工具&#xff0c;并在诸如jcmd &#xff0c; jps &#xff0c; jstat &#xff0c; jinfo &#xff0c; jhat和jmap &#xff0c; jrunscript &#xff0c; jstack之类的 工…

佳能2900打印机与win10不兼容_佳能2900打印机和惠普1020哪种好 佳能2900打印机和惠普1020对比【详解】...

现在的人们早已经习惯遇到身边美丽的景色&#xff0c;就用手机进行拍摄下来了&#xff0c;若想长久的留住这一刻的美好&#xff0c;拥有一台 打印机 就是很不错的选择&#xff0c;如今打印机的需求量在不断的增加&#xff0c;市面上的打印机品牌也在不断的增多&#xff0c;我们…

Sublime Text for Windows的快捷键

文章目录选择文本移动光标编辑类查找/替换窗口显示书签其它选择文本 快捷键说明CtrlD先选中文本&#xff0c;再按CtrlD&#xff0c;会选中下一个相同的文本&#xff0c;再继续按D(Ctrl不放)则会选中下一个相同的文本&#xff0c;可以同时编辑被选中的文本AltF3选中文本按下快捷…

mysql 多表查询 join on_mysql多表查询

在做连表查询的时候&#xff0c;可以在联合的字段上面&#xff0c;分别加上索引字段&#xff0c;这样有加快搜索的速度左右连表查询时条件放在on后面和where后面的执行时机是不一样的例如test1表test2表执行SELECT * FROM test1 t1 LEFT JOIN test2 t2ON t1.not2.no AND t2.nam…

java 多模块模块变灰色_到底谁需要Java模块?

java 多模块模块变灰色拼图问题为1000。我作为X想要JPMS模块。 如果不是平台开发人员&#xff0c;X是什么&#xff1f; 我的回答是X是人&#xff08;减去平台开发人员&#xff0c;因为那是一个条件&#xff09; 。 我们都需要模块系统具有更安全的代码&#xff0c;从而产生更可…

python如何保持数据类型不变_python 可变和不可变数据类型、格式化输出和基础运算符...

一、可变类型和不可变类型#可变类型&#xff1a;在id不变的情况下&#xff0c;value可以变&#xff0c;则称为可变类型&#xff0c;如&#xff1a;列表&#xff0c;字典#不可变类型&#xff1a;value一旦改变&#xff0c;id也改变&#xff0c;则称为不可变类型(id变&#xff0c…

MacBook Air的命令终端如何在root和普通用户之间切换

有时你需要在一些root级别的目录下创建和删除文件&#xff0c;如果你没有切换到root用户下&#xff0c;系统会提示你没有权限&#xff0c;如下所示&#xff1a; liaowenxiongdeMacBook-Air:local liaowenxiong$ mkdir test mkdir: test: Permission denied liaowenxiongdeMacB…

mysql导入数据显示进度条_导入数据思路+进度条

/// ///基础数据导入/// private voidLoadBasicData(){this.NowCount 0;this.AllCount 0;this.hasResult false;try{DelegateShowProssBar mi newDelegateShowProssBar(ShowProcessBar);this.BeginInvoke(mi, new object[] { "导入基础数据", "导入数据"…

redis key失效的事件_《分享几道高频 Redis 高频面试题,面试不用愁》

1、说说 Redis 都有哪些应用场景&#xff1f;缓存&#xff1a;这应该是 Redis 最主要的功能了&#xff0c;也是大型网站必备机制&#xff0c;合理地使用缓存不仅可以加 快数据的访问速度&#xff0c;而且能够有效地降低后端数据源的压力。共享Session&#xff1a;对于一些依赖 …

mysql按加号没反应_请各位大哥给小老弟解疑答惑一下 为什么点击加号没有反应?感谢...

事件function count(){var sum;//获取第一个输入框的值var aparseFloat(document.getElementById("txt1").value);//获取第二个输入框的值var bparseFloat(document.getElementById("txt2").value);//获取选择框的值var cdocument.getElementById("se…

解决文件内容的中文乱码_字符集_字符编码_字符编码方案

从第三方下载的java源文件&#xff0c;打开查看里面的中文全部是乱码&#xff0c;无论你使用什么字符编码集都无法正常显示&#xff0c;该文件是用UTF-8编码存档的&#xff0c;使用UTF-8解码也同样是乱码&#xff0c;相信很多人遇到类似的问题&#xff0c;我这里解决过一个经典…

安卓清理垃圾清理代码_从战中清理代码

安卓清理垃圾清理代码从战中清除代码–验证 让我们直接从一个例子开始。 考虑一个简单的Web服务&#xff0c;该服务允许客户向商店下订单。 订单控制器的非常简化的版本可能如下所示– RestController RequestMapping(value "/",consumes MediaType.APPLICATION_J…

rust为什么显示不了国服_捋捋 Rust 中的 impl Trait 和 dyn Trait

缘起一切都要从年末换工作碰上特殊时期, 在家闲着无聊又读了几首诗, 突然想写一个可以浏览和背诵诗词的 TUI 程序说起. 我选择了 Cursive 这个 Rust TUI 库. 在实现时有这么一个函数, 它会根据参数的不同返回某个组件(如 Button, TextView 等). 在 Cursive 中, 每个组件都实现了…

Sublime Text for Mac的快捷键

文章目录选择文本移动光标编辑文本查找/替换窗口显示书签和标记其它选择文本 快捷键说明CommandD先选中文本&#xff0c;再按CommandD&#xff0c;会选中下一个相同的文本&#xff0c;再继续按D(Command不放)则会选中下一个相同的文本&#xff0c;可以同时编辑被选中的文本Con…

zip unzip_zip和unzip上的Java要点

zip unzip压缩是编写文件时可以在我们的代码中发出的主要动作之一。 因此&#xff0c;我发现在zip和unzip上必不可少的简单Java代码段&#xff0c;并且必须易于访问。 要点是纯Java语言&#xff0c;并以zip格式存储两个文件。 完成后&#xff0c;打开打开的拉链并评估其内容。…