算法(2)-二叉树的遍历(递归/迭代)python实现

二叉树的遍历

  • 1.深度优先DFS
    • 1.1 DFS 递归解法
      • 1.1.1先序遍历
      • 1.1.2中序遍历
      • 1.1.3后序遍历
    • 1.2 DFS迭代解法
      • 1.2.1先序遍历
      • 1.2.2中序遍历
      • 1.2.3后序遍历
  • 2.广度优先BFS
  • 3.二叉树的最大深度
    • 3.1递归
    • 3.2迭代
  • 4.翻转二叉树
    • 4.1递归
    • 4.1迭代
  • 5.合并两棵二叉树
    • 5.1递归
    • 5.2迭代

有两种通用的遍历树的策略:深度优先遍历、广度优先遍历。
(树本身是一个递归的结构)

在这里插入图片描述
利用树类构造一个棵二叉树:

class TreeNode(object):def __init__(self, x):self.val = xself.left = Noneself.right = None
T=TreeNode(1)
n1=T.left=TreeNode(2)
n2=T.right=TreeNode(3)
n3=n1.left=TreeNode(4)
n4=n1.right=TreeNode(5)

1.深度优先DFS

DFS(Depth First Search)为二叉树的深度优先遍历方式,深度优先从根节点开始,往深处搜索至某个叶子节点,依据左孩子,右孩子,根节点的相对遍历顺序,可以分为先序遍历(根-左-右),中需遍历(左-根-右),后续遍历(左-右-根)。

1.1 DFS 递归解法

深度优先递归解法的三种顺序,框架一致。递归最重要的一点:递归结束条件,(1)当前节点为空,或者递归程序执行完最后一行。

1.1.1先序遍历

根-左-右 输出:[1,2,4,8,9,5,3,6,7]

class Solution(object):def PreOrder_rec(self,root):res=[]def DFS_pre(node,res):if node==None:           returnres.append(node.val)     # 先中DFS_pre(node.left,res)   # 递归左子树DFS_pre(node.right,res)  # 递归右子树DFS_pre(root,res)return res

1.1.2中序遍历

左-根-右 输出:[8,4,9,2,5,1,6,3,7]

class Solution(object):def InOrder_rec(self, root):res=[]def DFS_In(node,res):if node==None:returnDFS_In(node.left,res)res.append(node.val)DFS_In(node.right,res)DFS_In(root,res)return res

1.1.3后序遍历

左-右-根 输出[8,9,4,5,2,6,7,3,1]

class Solution(object):def BackOrder_rec(self, root):res=[]def DFS_Back(node,res):if node==None:returnDFS_Back(node.left,res)DFS_Back(node.right,res)res.append(node.val)DFS_Back(root,res)return res

1.2 DFS迭代解法

二叉树深度优先迭代 要借助(先进后出)的特点。依据三种不同的顺序将不同的节点压入堆栈。

1.2.1先序遍历

根-左-右 输出:[1,2,4,8,9,5,3,6,7]。维护一个堆栈stack(python中可以用List 高效实现)
从根结点开始(curr=Root);
如果当前节点非空 访问当前结点的值,将当前节点的右子树节点推入堆栈,更新当前结点:curr=curr.left.;
如果当前节点为空:弹出堆栈保存的最后一个右子树结点。

class Solution(object):def PreOrder_iter(self, root):""":type root: TreeNode:rtype: List[List[int]]"""res=[]stack=[]curr=rootwhile(curr or stack):if curr:res.append(curr.val)stack.append(curr.right)     # 递归到叶子结点时,会出现stack 增加None的情形curr=curr.left               # 将None pop 出来就是多了一次无增res操作else:curr=stack.pop()return res

1.2.2中序遍历

左-根-右 输出:[8,4,9,2,5,1,6,3,7]
维护一个堆栈stack(python中可以用List 高效实现)。
从根结点开始(curr=Root):
如果当前节点非空:将当前结点推入堆栈,更新当前结点:curr=curr.left;
如果当前节点为空:弹出堆栈保存的最后一个结点,访问该结点的值,更新当前结点:curr=curr.right.

class Solution(object):def InOrer_iter(self, root):""":type root: TreeNode:rtype: List[List[int]]"""res=[]stack=[]curr=rootwhile(curr or stack):if curr:stack.append(curr)curr=curr.left      # 一直搜索左子树到叶子节点,将路径上的结点推入堆栈else:                   curr=stack.pop()res.append(curr.val)curr=curr.right    # 访问右子树结点return res

1.2.3后序遍历

左-右-根 输出[8,9,4,5,2,6,7,3,1]
维护一个堆栈stack(python中可以用List 高效实现)。
从根结点开始(curr=Root):
如果当前节点非空:将当前结点推入堆栈,更新当前结点:curr=curr.left;
如果当前节点为空:弹出堆栈保存的最后一个结点,访问该结点的值,更新当前结点:curr=curr.right.

class Solution(object):def BackOrder_iter(self, root):""":type root: TreeNode:rtype: List[List[int]]"""res=[]stack=[]curr=rootwhile(curr or stack):  # 左右根尅分解为:根右左+逆序(根右左和根左右是一样的实现框架)if curr:res.append(curr.val)stack.append(curr.left)curr=curr.rightelse:curr=stack.pop()return res[::-1]

2.广度优先BFS

BFS(Breadth First Search)为二叉树的广度优先遍历方式,又叫层次遍历从根节点开始逐层遍历二叉树。1->2->3->4->5->6->7->8->9

借助队列 先进后出 的特点,将节点不断推入队列中。python 中用list可以快速实现队列。
迭代解法 输出[1,2,3,4,5,6,7,8,9]

class Solution(object):def BFS_iter1(self, root):""":type root: TreeNode:rtype: List[List[int]]"""levels=[]queue=[root]if  not root:return levelswhile(queue):      # node=queue.pop(0)        levels.append(node.val)if node.left:            # 装进队列里的元素都是非空的。queue.append(node.left)if node.right:queue.append(node.right)return levels

leetcode 102 要求输出的结果每一层的元素放在一起,则需要维护一个list,用于放置每层的元素,levels=[[1],[2,3],[4,5,6,7],[8,9]],同时一个level变量用于指示当前节点位于的层数。

迭代解法 :输出[[1],[2,3],[4,5,6,7],[8,9]]

class Solution(object):def levelOrder_iter2(self, root):""":type root: TreeNode:rtype: List[List[int]]"""levels=[]queue=[root]if  not root:return levelswhile(queue):      # 处理每一层前,增加一次levels,装该层的节点值levels.append([])n_q=len(queue)  # 该层节点个数for i in range(n_q): # i:[0,n_q-1] # 逐个处理该层节点:首先弹出队列首,记录数值,有左右孩子的将孩子压入队列node=queue.pop(0)levels[-1].append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)return levels

递归解法 输出[[1],[2,3],[4,5,6,7],[8,9]]
实际上是利用DFS实现的BFS,每当DFS遍历到一个新的节点,就把它加入到所在层的list里面去。

class Solution(object):def levelOrder_rec(self, root):""":type root: TreeNode:rtype: List[List[int]]"""levels=[]if  not root:return levelsdef BFS_rec(node,level):if len(levels)==level:        # level作为levels 的索引,应该<len(levels),如果相等,则需要增加levels的装载能力,扩容levels.append([])levels[level].append(node.val)  # 将当前节点放入指定的层if node.left:					# 如果有左右孩子,递归调用BFS_recBFS_rec(node.left,level+1) if node.right:BFS_rec(node.right,level+1)BFS_rec(root,0)return levels

参考博文:
二叉树的前中后遍历,层次遍历,树的递归问题(递归与迭代python):https://www.cnblogs.com/liuyicai/p/10156455.html
二叉树及其遍历方法—python实现:https://www.cnblogs.com/lliuye/p/9143676.html

3.二叉树的最大深度

3.1递归

def Max_depth(node):if node==None:return 0dl=DFS(node.left)dr=DFS(node.right)res=max(dl,dr)+1return res
res=Max_depth(root)
return res

3.2迭代


def maxDepth(self, root):de=0if root:stack=[(1,root)]else:return 0while(stack):cur_de,node=stack.pop()if node:     # 只有当结点存在时+1后的深度才会被采用de=max(de,cur_de)stack.append((cur_de+1,node.left))stack.append((cur_de+1,node.right))return de

4.翻转二叉树

4.1递归

自低向上的交换过程

class Solution(object):def invertTree(self, root):if root==None:returnself.invertTree(root.left)self.invertTree(root.right)root.left,root.right=root.right,root.leftreturn root

4.1迭代

自顶向下的交换过程

class Solution(object):def invertTree(self, root):""":type root: TreeNode:rtype: TreeNode"""if root:q=[root]else:return rootwhile(q):curr=q.pop(0)curr.left,curr.right=curr.right,curr.leftif curr.left:q.append(curr.left)if curr.right:q.append(curr.right)return root

5.合并两棵二叉树

leetcode617: 两棵树有公共结点处的值为两数对应节点值想加

5.1递归

class Solution(object):def mergeTrees(self, t1, t2):if not t1 and not t2:return Noneroot=TreeNode(0)if t1 and t2:root.val=t1.val+t2.valroot.left=self.mergeTrees(t1.left,t2.left)root.right=self.mergeTrees(t1.right,t2.right)elif t1:root.val=t1.valroot.left=self.mergeTrees(t1.left,None)root.right=self.mergeTrees(t1.right,None)else:root.val=t2.valroot.left=self.mergeTrees(None,t2.left)root.right=self.mergeTrees(None,t2.right)return rootclass Solution(object):def mergeTrees2(self, t1, t2):if t1==None:return t2if t2==None:return t1t1.val+=t2.valt1.left=self.mergeTrees2(t1.left,t2.left)t1.right=self.mergeTrees2(t1.right,t2.right)return t1

5.2迭代

首先把两棵树的根节点入栈,栈中的每个元素都会存放两个根节点,并且栈顶的元素表示当前需要处理的节点。
以t1作为最后的输出返回,
当前结点的处理( 在stack里面的东西都是非空的):
两者相加的值放入t1.val
子结点的处理:
t1没有做孩子,t2的左孩子给t1.
t1,t2同时有左孩子,将其同时入栈,
右孩子的处理同理。

class Solution(object):def mergeTrees(self, t1, t2):if t1==None:return t2if t2==None:return t1stack=[(t1,t2)]while(stack):node1,node2=stack.pop() # 在stack里面的东西都是非零的node1.val+=node2.valif node1.left==None:node1.left=node2.leftelif node1.left and node2.left:  # 1.left 和2.left同时非零stack.append([node1.left,node2.left])if node1.right==None:node1.right=node2.right      # 放过来之后就有。elif  node1.right and node2.right:  # 1.left 和2.left同时非零stack.append([node1.right,node2.right])return t1

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

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

相关文章

libxml的安装和相关数据结构详解

1安装 一般如果在安装系统的时候选中了libxml开发库的话&#xff0c;系统会默认安装。如果没有安装&#xff0c;可以按如下步骤进行手工安装。 ① 从xmlsoft站点或ftp(ftp.xmlsoft.org)站点下载libxml压缩包 (libxml2-xxxx.tar.gz) ② 对压缩包进行解压缩 tar xvzf …

内核中的 likely() 与 unlikely()

在 2.6 内核中&#xff0c;随处可以见到 likely() 和 unlikely() 的身影&#xff0c;那么为什么要用它们&#xff1f;它们之间有什么区别&#xff1f; 首先要明确&#xff1a; if(likely(value)) 等价于 if(value) if(unlikely(value)) 也等价于 if(value) 也就是说 likely()…

python外卷(12)-sort(),sorted(),ord(),chr()

Python内置函数1.sort()&#xff0c;sorted()2.ord(), chr()1.sort()&#xff0c;sorted() sort() 是list的方法&#xff0c;对已经存在的列表进行操作&#xff0c;无返回值 a[3,2,4,1] b["c","a","b"] print (a.sort(),b.sort()) # 输出 (Non…

利用posix_fadvise清理系统中的文件缓存

利用posix_fadvise清理系统中的文件缓存leoncom c/c,unix2011-08-03当我们需要对某段读写文件并进行处理的程序进行性能测试时&#xff0c;文件会被系统cache住从而影响I/O的效率&#xff0c;必须清理cache中的对应文件的才能正确的进行性能测试。通常清理内存可以采用下面的这…

空间分配

目前主流的垃圾收集器都会采用分代回收算法&#xff0c;因此需要将堆内存分为新生代和老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 大多数情况下&#xff0c;对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时&#xff0c;虚拟…

关于uint32_t uint8_t uint64_t 的问题

怎么又是u又是_t的?u代表的是unsigned相信大家都知道,那么_t又是什么呢?我认为它就是一个结构的标注,可以理解为type/typedef的缩写,表示它是通过typedef定义的,而不是其它数据类型。 uint8_t,uint16_t,uint32_t等都不是什么新的数据类型,它们只是使用typedef给类型起…

学点数学(4)-协方差矩阵

协方差矩阵协方差矩阵&#xff08;从随机变量讲起&#xff09;随机变量x&#xff1a;表示随机试验各种结果的 实值 单值函数&#xff0c;就是说随机变量x是一个函数映射&#xff0c;其取值为标量。随机变量有离散型和连续型&#xff0c;离散型&#xff1a;抛10次硬币&#xff…

RedLock

概念 Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock&#xff0c;此种方式比原先的单节点的方法更安全。它可以保证以下特性&#xff1a; 安全特性&#xff1a;互斥访问&#xff0c;即永远只有一个 client 能拿到锁避免死锁&#xff1a;最终…

GCC中常用的优化的参数

-pipe 的作用&#xff1a; 使用管道代替编译中临时文件&#xff0c; -pipe 加速编译 gcc -pipe foo.c -o foo 加速 在将源代码变成可执行文件的过程中,需要经过许多中间步骤,包含预处理、编译、汇编和连接。这些过程实际上是由不同的程序负责完成的。大多数情况下 GCC 可以为 …

Linux与时间相关的结构体及相关用法

1. Linux下与时间有关的结构体 struct timeval { int tv_sec; int tv_usec; }; 其中tv_sec是由凌晨开始算起的秒数&#xff0c;tv_usec则是微秒(10E-6 second)。 struct timezone { …

算法(3)-数据结构-数组和字符串

leetcode-explore-learn-数据结构-数据结构-数组和字符串1. 一维数组1.0 概况1.1 寻找数组的中心索引1.2 搜索插入位置1.3 合并区间1.4 至少是其他数字两倍大的最大数1.5 加一2. 二维数组2.1旋转矩阵本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处…

redis的入门/原理/实战大总结

入门 Redis是一款基于键值对的NoSQL数据库&#xff0c;它的值支持多种数据结构&#xff1a; 字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。 • Redis将所有的数据都存放在内存中&#xff0c;所以它的读写性能十分惊人&#xff0c;用作数…

创建与打开IPC通道的POSIX和SYSTEM V方法

先说&#xff30;&#xff2f;&#xff33;&#xff29;&#xff38;的吧&#xff1a; mq_open&#xff0c;sem_open&#xff0c;shm_open着三个函数用于创建或者打开一个IPC通道。 由此可见&#xff0c;消息队列的读写权限是任意的&#xff0c;然而信号灯就没有&#xff0c;…

算法(4)-leetcode-explore-learn-数据结构-数组2

leetcode-explore-learn-数据结构-数组21.简述2.例题2.1 二维数组的对角线遍历2.2 螺旋遍历2.3 杨辉三角本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn.com/explore/learn/card/ar…

软件测试基础知识

第一章 1.1 软件测试背景知识和发展史 互联网公司职位架构&#xff1a;产品 运营 技术 市场 行政软件测试&#xff1a;使用人工或自动化手段&#xff0c;来运行或测试某个系统的过程&#xff0c;其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别&#…

key_t IPC键和ftok函数详解和剖析

统建立IPC通讯&#xff08;如消息队列、共享内存时&#xff09;必须指定一个ID值。通常情况下&#xff0c;该id值通过ftok函数得到。 ftok原型如下&#xff1a; key_t ftok( char * fname, int id ) fname就时你指定的文件名(该文件必须是存在而且可以访问的)&#xff0c;id是子…

算法(5)-leetcode-explore-learn-数据结构-字符串

leetcode-explore-learn-数据结构-数组3-字符串1.简述2.例题2.1 二进制求和2.2实现strStr()2.3最长公共前缀本系列博文为leetcode-explore-learn子栏目学习笔记&#xff0c;如有不详之处&#xff0c;请参考leetcode官网&#xff1a;https://leetcode-cn.com/explore/learn/card…

ipcs命令查看管道,消息队列,共享内存

修改消息队列大小&#xff1a; root&#xff1a;用户&#xff1a; /etc/sysctl.conf kernel.msgmnb 4203520 #kernel.msgmnb 3520 kernel.msgmni 2878 保存后需要执行 sysctl -p ,然后重建所有消息队列 ipcs -q : 显示所有的消息队列 ipcs -qt : 显示消息队列的创建时…

Jmeter-基础篇

常用压力测试工具对比 1、loadrunner 性能稳定&#xff0c;压测结果及细粒度大&#xff0c;可以自定义脚本进行压测&#xff0c;但是太过于重大&#xff0c;功能比较繁多 2、apache ab(单接口压测最方便) 模拟多线程并发请求,ab命令对发出负载的计算机…

消息队列接口API(posix 接口和 system v接口)

消息队列 posix API消息队列&#xff08;也叫做报文队列&#xff09;能够克服早期unix通信机制的一些缺点。信号这种通信方式更像\"即时\"的通信方式&#xff0c;它要求接受信号的进程在某个时间范围内对信号做出反应&#xff0c;因此该信号最多在接受信号进程的生命…