树在面试中真的是一个出镜率异常高的数据结构了。而且和递归结合紧密,作为手撸代码的考察真是再合适不过。
所以就在这篇日记里不断更新树的一些概念和相应的题目吧~
我的梦想是!一文在手!天下我有!

树的手撸代码中常常涉及到的知识

  • 树的深度

    • 递归 / 非递归
  • 树的高度
    • 递归
    • 非递归: 可以层序
    • 平衡树
  • 树的结点
    • 结点数
    • 求下一个结点:前中后序
  • 数的遍历
    • 前中后序遍历

      • 递归
      • 非递归:栈/队列辅助
    • 层序遍历(队列辅助)
      • 层序遍历一棵树
      • 逐层打印一棵树
      • 之字形打印一棵树等等
    • 前序+中序 / 后序+中序重建一棵树
  • 子树
  • 树的镜像
  • 二叉树
  • 二叉平衡树
    • 左右子树高度差不超过1
  • 二叉搜索树
    • 左子树永远小于等于右子树
  • 树的路径

面试还可能问到

  • 红黑树
  • B树
  • B+树

先写一棵树

你一定要会写树的结点定义啊

# 没有指向老父亲的结点指针的树结点
class TreeNode():def __init__(self,x):self.val = xself.left = Noneself.right = None
# 有指向父亲的结点指针的树结点
class TreeNode2():def __init__(self,x):self.val = xself.left = Noneself.right = Noneself.next = None # 父指针

然后呢?结点写出来了不会写出一棵树来测试自己的代码丢不丢人。。。

# Test:
#        10
#       /  \
#      5   12
#     / \
#    4   7
value = [10,5,12,4,7]
node = []
# 初始化这些结点
for val in value:node.append(TreeNode(val))
# 然后把结点连起来
node[0].left = node[1]
node[0].right = node[2]
node[1].left = node[3]
node[1].right = node[4]# 或者这样
node_var = [10,9,8,7,6,5]
node = []
for item in node_var:node.append(TreeNode(item))i = 0
while 2*i+1<len(node):node[i].left = node[2*i+1]if 2*i+2<len(node):node[i].right = node[2*i+2]i+=1

然后是树的遍历!

这个不管是递归还是非递归,手撸的概率很高。之前阿里的暑期实习就要求我写一个非递归的中序遍历。
非递归可以写出各种版本。但是可以用一个统一的逻辑概括起来。便于记住。如下图所示。

当然还可以有其他逻辑。我就不贴出来了。
太多会乱。统一起来便于记忆!
详细的递归 / 非递归代码如下

class Tranverse():# 递归先序def preOrderIter(self,root):if not root:return []res =[]res.append(root.val)left = self.preOrderIter(root.left)right = self.preOrderIter(root.right)res += left+rightreturn res# 非递归先序# 用一个栈辅助的话,先右孩子在左孩子入栈# 用一个队列,那就pop(0),先左后右def preOrderNoIter(self,root):if not root:return []res =[]stack =[root]while stack:# 元素出栈root = stack.pop()# 访问这个元素res.append(root.val)# 先右if root.right:stack.append(root.right)# 再左if root.left:stack.append(root.left)return res# 递归中序def inOrderIter(self,root):if not root:return []res =[]left = self.inOrderIter(root.left)res += leftres.append(root.val)right = self.inOrderIter(root.right)res += rightreturn res# 非递归中序def inOrderNoIter(self,root):if not root:return []res =[]stack =[]# 如果栈不空或者结点存在while stack or root:#结点存在while root:# 结点入栈并向左子树stack.append(root)root = root.left# 左孩子空了跳出循环。如果栈不空if stack:# 元素出栈并访问root = stack.pop()res.append(root.val)# 然后访问右子树root = root.rightreturn res# 递归后序def postOrderIter(self,root):if not root:return []res =[]left = self.postOrderIter(root.left)right = self.postOrderIter(root.right)res += left+rightres.append(root.val)return res# 非递归后序# 按照根-右-左的顺序存储到res,然后倒序输出# 可以直接对照先序非递归来写def postOrderNoIter1(self,root):if not root:return []stack = [root]res = []while stack:root = stack.pop()# res 存储根res.append(root.val)# 先压栈左孩子,之后会后存入resif root.left:stack.append(root.left)# 后压入右孩子,之后会先弹出先存入resif root.right:stack.append(root.right)return res[::-1]def postOrderNoIter2(self,root):if not root:return []res = []stack =[]while stack or root:while root:stack.append(root)res.append(root.val)root = root.rightif stack:root = stack.pop()root = root.leftreturn res[::-1]# 层序遍历def layerOrder(self,root):if not root:return []res =[]queue =[root]while len(queue)>0:root = queue.pop(0)res.append(root.val)if root.left:queue.append(root.left)if root.right:queue.append(root.right)return res

然后数一下树的结点

其实数树的的结点数有很多办法。
比如可以用任意一种遍历,每次访问一个结点就计数。或者返回结点值列表的长度。
也可以这样直接递归数:

def treeNodeNums(root):if not root:return 0nums = treeNodeNums(root.left)+treeNodeNums(root.right) + 1# 当然这里也可以写:# left = treeNodeNums(root.left)# right = treeNodeNums(root.right)# nums = left+right+1return nums

再然后求一下树的深度

树的深度当然也可以用递归或者非递归方法求。
非递归的话可以借助一下层序遍历
递归的话就很类似于数结点数了:

def treeDepth(root):if not root:return 0# 左子树深度left = treeDepth(root.left)# 右子树深度right = treeDepth(root.right)return max(left,right)+1

【刷题日记】树的那些事儿(一)——基本操作相关推荐

  1. 一个算法笨蛋的12月leetCode刷题日记

    类似文章 一个算法笨蛋的2021年11月leetCode刷题日记 一个算法笨蛋的2021年12月leetCode刷题日记 一个算法笨蛋的2022年1月leetCode刷题日记 一个算法笨蛋的2022年 ...

  2. leetcode刷题之树(三)

    翻转二叉树,感觉做二叉树的问题好像都是那一套公式,除了个别的问题解决不了,用上篇博客leetcode刷题之树(二)的模型基本可以解决.总体来说就是树基本都可以利用递归和迭代的方法去解决,在涉及到树的遍 ...

  3. 菜菜的刷题日记 | 66.加一 Plus One

    系列索引:菜菜的刷题日记 | 被LeetCode用Python狂虐的那段日子 菜鸡的刷题之路--2022/1/7 文章目录 [题目] [我的代码] [参考代码1] [参考代码2] [参考代码3] [思 ...

  4. 牛客刷题日记(2021-12-8)

    牛客刷题日记(2021-12-8) 题目: 以下哪个接口的定义是正确的?( )interface B { void print() { } ;}interface B { static void pr ...

  5. 刷题日记【第十三篇】-笔试必刷题【数根+星际密码+跳台阶扩展问题+快到碗里来】

    刷题日记[第十三篇]-笔试必刷题[数根+星际密码+跳台阶扩展问题+快到碗里来] 1.方法区在JVM中也是一个非常重要的区域,它与堆一样,是被[线程共享]的区域. 下面有关JVM内存,说法错误的是?(c ...

  6. CTFshow刷题日记-MISC-图片篇(上)基础操作和信息附加

    ctfshow 图片篇引语 大部分题目仅涉及单一知识点,但可能有多种解法: 找到flag并不困难,关键是了解每一题背后的原理: 藏在哪?为什么可以这样藏?请多考虑这两个问题: misc脑图-misc之 ...

  7. 牛客刷题日记(2021-11-24)

    牛客刷题日记(2021-11-24) 题目: 下面程序的输出是:() String x="fmn"; x.toUpperCase(); String y=x.replace('f' ...

  8. Leetcode刷题日记(十二)

    又是老台词:欢迎大家来到一晚一度的leetcode刷题日记时间.今天我们来讲讲队列的问题,队列这方面的基础知识需要的同学到博主前面的文章找吧.队列这方面的问题平时博主也是接触得比较少的.下面是一道利用 ...

  9. 菜菜的刷题日记 | 蓝桥杯 — 十六进制转八进制(纯手撕版)附进制转换笔记

    系列索引:菜菜的刷题日记 | 被LeetCode用Python狂虐的那段日子 万万没想到啊,回老家过年断更的几天之后,我会因为无聊在除夕这天做了会儿题,然后写篇题解. 文章目录 [题目] [我的代码] ...

  10. 菜菜的刷题日记 | 12.整数转罗马数字

    系列索引:菜菜的刷题日记 | 被LeetCode用Python狂虐的那段日子 菜鸡的刷题之路--2022/1/24,这几天忙着肝并发编程,题在做但是没空写题解,今晚补一篇. 文章目录 [题目] [官方 ...

最新文章

  1. IPV6在WINXP、WIN2003、WIN7下的网络配置
  2. 建立合理的索引提高SQL Server的性能
  3. 切换ip下的sql server用户权限丢失_Zabbix_server高可用之文件同步
  4. Python模块学习——tempfile
  5. 容器编排技术 -- Kubernetes kubectl annotate 命令详解
  6. Arcgis Android API开发之离线地图
  7. 论坛介绍 | COSCon'22 开源文化
  8. PureMVC框架知识介绍
  9. 数据分析(Python)贡献度分析——帕累托法则
  10. 至高心法 - SpringCloud Alibaba (二)Nacos 服务注册与配置中心
  11. python中len方法
  12. arduino学习笔记十八--红外遥控检测
  13. 怎样安装win服务器系统,win服务器系统安装教程
  14. Vue 中常见的面试题/知识点整理
  15. P1472 奶牛家谱 Cow Pedigrees
  16. PS2键盘第二套键盘扫描码学习发现
  17. js replace() 使用
  18. 苏大强说:这才是最适合SOHO的客户开发方法
  19. 在Amazon SageMaker上快速、灵活构建Amazon TensorFlow模型的在线推理服务
  20. posix_memalign函数详解以及使用时的注意事项

热门文章

  1. MINIX - 磁盘块和缓冲块
  2. Github星标90K?京东架构师一篇讲明白百亿级并发系统架构设计
  3. [旅游]300元走遍上海周边最美的古镇
  4. web2.0常用网页配色
  5. 全平台小程序开发框架Uni-app重点概览
  6. Mac配置maven环境与settings设置
  7. 根据搜索词使得搜索结果中的关键词改变颜色
  8. 十位安卓开发者的 17 年总结
  9. nn.KLDivLoss
  10. python爬取驴妈妈旅游桂林周边景点信息