网站首页 > 技术文章 正文
大家通常认知的二叉树如下所示:
数据结构如下定义:
class Node:
def __init__(self,val,left=None,right=None):
self.val = val
self.left = left
self.right = right
换成链表视角的话,可以这样看待二叉树:
可以理解成常规的链表只有一个next节点,二叉树有两个next节点,只不过我们把这两个next节点通常理解和表示成左孩子和右孩子。既然和链表性质很像,类比来看,可以认为二叉树基本继承了链表的一些性质:
①增加节点和删除节点的效率会比较高,随机访问效率会比较低。
②可以用递归来操作二叉树
实际上,绝大多数情况时候使用递归的形式来操作二叉树,具体做法是对二叉树的左子树和右子树递归进行操作即可。
下面是一些常见的练习或面试题,最好做到熟练掌握:
准备工作,通过函数创建上述二叉树:
arr = [10 ,6 ,4 ,-1, -1, 7, -1 ,9 ,-1 ,-1, 12 ,-1 ,16, 15 ,-1 ,-1 ,20, -1, -1]
def create_bin_tree(arr,i):
if arr and i >= len(arr):
return None,i
if arr[i] == -1:
return None,i
tree = Node(arr[i])
tree.left, j = create_bin_tree(arr,i+1)
tree.right,k = create_bin_tree(arr,j+1)
return tree,k
tree,_ = create_bin_tree(arr,0)
① 前序遍历:先打印当前节点,然后递归前序访问A,最后递归前序访问B,代码类似如下
def pre_order(tree):
if not tree:
return
print(tree.val)
pre_order(tree.left)
pre_order(tree.right)
②中序遍历:先递归中序访问A,再打印当前节点,最后递归中序访问B,代码:
def mid_order(tree):
if not tree:
return
mid_order(tree.left)
print(tree.val)
mid_order(tree.right)
③后续遍历:先递归后续遍历A,再递归后续遍历B,再访问当前节点
def post_order(tree):
if not tree:
return
post_order(tree.left)
post_order(tree.right)
print(tree.val)
④求二叉树的高度: 先递归求A的高度,再递归求B的高度,取二者中最大值+1
def get_height(tree):
if not tree:
return 0
left_height = get_height(tree.left)
right_height = get_height(tree.right)
return 1+max(left_height,right_height)
⑤求二叉树的镜像: 将当前节点的A和B部分互换,递归求A和B的镜像
def mirror(tree):
if not tree:
return None
temp = tree.left
tree.left = tree.right
tree.right = temp
mirror(tree.left)
mirror(tree.right)
return tree
⑥求二叉树的节点数:先求A的节点数,再求B的节点数,二者的和加1
def get_node_count(node):
if not node:
return 0
left_node_count = get_node_count(node.left)
right_node_count = get_node_count(node.right)
return 1 + left_node_count + right_node_count
⑦求二叉树的叶子节点数:如果当前节点无孩子节点,则返回1;否则递归调用A和B的叶子节点并相加。
def get_leaf_count(node):
if node == None:
return 0
if node.left == None and node.right==None:
return 1
return get_leaf_count(node.left)+get_leaf_count(node.right)
⑧广度遍历二叉树:初始化时,将二叉树的根节点放到队列中;后续每次从队列取一个节点,将其左右孩子放到队列中,接着递归调用即可。
def BFS(queue):
if not queue:
return
node = queue[0]
print(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
del queue[0]
BFS(queue)
queue = [tree]
BFS(queue)
⑨通过前序和中序构建二叉树:
前序:10 6 4 7 9 12 16 15 20
中序:4 6 7 9 10 12 15 16 20
核心思想:通过前序数组可以得知根节点,通过中序可以将根节点的左右孩子,也就是A和B找出来,然后递归调用即可。如下图所示:
本代码的主要细节是下标的处理,见下图所示:
代码如下:
def create_bin_tree_pre_mid(pre_trans,i,j,mid_trans,m,n):
if i>j or m>n:
return None
pivot = pre_trans[i]
s = m
while s<=n:
if mid_trans[s] == pivot:
break
s+=1
node = Node(pre_trans[i])
node.left = create_bin_tree_pre_mid(pre_trans,i+1,i+s-m,mid_trans,m,s-1)
node.right = create_bin_tree_pre_mid(pre_trans,i+s-m+1,j,mid_trans,s+1,n)
return node
tree2 = create_bin_tree_pre_mid(pre_trans,0,len(pre_trans)-1,mid_trans,0,len(mid_trans)-1)
从上面的例子也可以看出,学好递归的重要性,递归本身是一种自顶向下的思维方式,比较容易掌握,实际编程中也非常有用,值得我们练习和掌握。关于递归更深入的例子和探讨,可以查看笔者的算法求解思路培养系列。算法求解思路培养-2. 八皇后问题(说说递归) 算法求解思路培养-5.从递归到动态规划 算法求解思路培养-4.棋盘覆盖问题(递归终结篇) 算法求解思路培养-3.链表反转(链表和递归结合) 算法求解思路培养-6.动态规划之凸多边形剖分 算法求解思路培养-9.动态规划之最大连续子串和 算法求解思路培养-7.最长公共子序列问题求解(从递归到非递归)
猜你喜欢
- 2024-09-09 序列化 Python 对象(序列化对象需要实现的接口)
- 2024-09-09 Meta 如何将缓存一致性提高到 99.99999999
- 2024-09-09 自学Python笔记2(python0基础自学书)
- 2024-09-09 找到两个链表的第一个公共节点(找出两个链表的第一个公共节点)
- 2024-09-09 详解SkipList跳跃链表(跳表遍历)
- 2024-09-09 Python画豪华版圣诞树,带漂亮彩灯与文字背景
- 2024-09-09 零基础Python完全自学教程23:函数的返回值、作用域和匿名函数
- 2024-09-09 redis的内存满了之后,redis如何回收内存
- 2024-09-09 「python小游戏」据说这是一款还原度超高的小游戏,你感受下....
- 2024-09-09 高阶Python|返回类型提示技巧 (1)
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)