在写完了全部线性数据结构以后,今天开启非线性数据结构系列。html
咱们今天先来看,什么是“树”。java
树是由顶点和边组成的且不存在环的数据结构。做为一个应用很是广的数据结构,不只在工做中经常使用,在面试中也很是常考。node
一是由于树的结构自然决定了它和递归联系紧密,不少树相关的算法题都很是适合用递归来解;web
二是由于它的难度介于链表和图之间,很是适合在 45 分钟的面试里进行考察,因此一场面试中遇到两三轮问树都是再正常不过的了。面试
本文先来说树的基础内容,分为如下小节,每一个小节开头都会有思惟导图和对应的 Leetcode
算法题哟~算法
DFS
遍历方式BFS
遍历方式鉴于树相关的内容太多,并且又是面试重点内容,以后会有文章再专门来说树有关的解题思路以及最经常使用的二叉搜索树,你们敬请期待~数组
其实数据结构里的“树”和咱们现实世界里的树挺像的,只不过倒过来了嘛,根朝上。数据结构
好比:svg
在这片森林里,最经常使用的仍是「二叉树」。post
二叉树,是由不少个 TreeNode
构成的这种树形的数据结构,
class TreeNode { int value; TreeNode left; TreeNode right; }
就像链表中的 ListNode
。
二叉树并不必定非得是“二叉”的,而是说每一个节点最多有两个孩子,叫 left
和 right
,但也能够没有。
当每一个节点都只有一个孩子的时候,就退化成了链表。
因此链表就是一棵特殊的树,而树是一个特殊的图。
你们知道我是金融背景的,因此我最开始了解二叉树是在金融工程课程中给衍生品订价,这里也简单梳理下,不感兴趣的小伙伴能够跳过这一段。
在金融工程里,二叉树是用来在风险中性世界里给期权订价使用的模型。
好比这是一个股价二叉树,其实就是咱们把二叉树放倒了看嘛。
有些小伙伴会发现,这里的节点好像少了不少,没错,由于咱们让股价每次上涨和下跌的幅度保持不变,因此到第 n 层最多有 n 个节点,而不会像普通的二叉树同样按照等比序列增加。
上图是两期的二叉树,那么最简单的一期的二叉树订价模型表示为:
咱们假设当前股票的价格为 S
,那咱们想知道将来某个时刻好比 t 时刻
的价格,股价有可能上涨也有可能下跌,还可能不变呢。
在该模型里咱们就抽象成两种可能性,一种是上涨,一种是下跌,因此能够用二叉树来表示。
假设股票价格会有 p
的几率上涨至 uS
,
有 1-p
的几率下跌至 dS
.
这里的 p
并非在真实世界里股票上涨的几率,而是一个在风险中性世界里的上涨几率,因此
股票如今的价格就是将来某时刻的无风险收益的折现,
即:
S = e − r t [ p S u + ( 1 − p ) S d ] S = e^{-rt}[pS_u + (1-p) S_d] S=e−rt[pSu+(1−p)Sd]
这就是最简单的二叉树订价模型。
那咱们言归正传。
树的三大特色是:
若是把树当作一个无向图,那么它是一个连通图 connected graph
.
树是一个无环图。
树的节点个数和边的个数之间的关系是固定的。若是树上有 n
个 node
,那么它有 n-1
条边。由于除了根节点,其余的节点都会有一条边指向它。
2.1 平衡二叉树 Balanced Binary Tree
:
这里要注意,是对于每一个节点,而不仅是对于根结点。
好比左边这棵树就不是平衡二叉树,右边的才是。
那么大名鼎鼎的 AVL-Tree
就是平衡二叉树,准确说是自平衡二叉查找树。
那什么是二叉查找树呢?
2.2 二叉查找树 Binary Search Tree
对二叉查找树,最重要的性质就是:
在作中序遍历时,这个序列是一个升序序列。
当你在作二叉查找树的算法题没有思路时,能够想一想这个性质,不少题目都会迎刃而解。
2.3 彻底二叉树 Complete Binary Tree
:
好比左边不是彻底二叉树,右边的是。
好比堆就是一个彻底二叉树,还不了解堆的基本操做的,公众号内回复「堆」获取文章复习哟~
那么彻底二叉树的最大的好处就是由于它排列紧密没有气泡,因此能够用数组来存储,这样就大大节省了内存空间。
2.4 完美二叉树 Perfect Binary Tree
完美二叉树比彻底二叉树的定义更加严格,包括最后一层,每一层的节点都要是满的,毕竟是追求完美的嘛。
因此咱们若是知道了层数,就知道了它有多少个节点,也就是一个等比数列求和。
2.5 完满二叉树 Full Tree
你们不要轻视这些概念哦,不少算法题都会直接考察,在本节的思惟导图里也附带了 Leetcode 对应的题目,电面时很喜欢考哦~
树的高度 height
和深度 depth
是两个很是重要的概念,好比 Leetcode 104 和 111 就是专门求树的高度的。
而这两个概念是相反方向的,大致上呢,
高度 Height
核心是,从该节点到最远叶子节点,有几条边。
这个概念在分析时空复杂度时很是经常使用,好比在树上作一个递归复杂度是 O(height)。
为何呢?
由于这个距离决定了在 call stack
上有多少层。
深度 Depth
这个概念用的比较少,是和高度方向相反的概念。
俗话说,横当作岭侧成峰,这句话用在这里太合适不过了。
对于树的几种遍历方式想必你们都不陌生,这就是我所说的「岭」;
而还有一种面试常考题是问 left/right/vertical/border view
,也就是求树的左视图、右视图、俯视图、border view 这我没找到中文翻译。。这就是我所说的「峰」。
先来总图:
最基本的三种遍历就是
pre order
in order
post order
其实这三种遍历方式本质都是同样的,只是输出/打印节点的顺序不一样罢了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zml9aI8f-1597109557048)(https://imgkr2.cn-bj.ufileos.com/c9765575-faa0-4320-ad18-ab627c1820f2.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=32%252FRA%252FaIpEYEMBv01iYr7K0HiuY%253D&Expires=1597102713)]
来看伪代码吧:
public void traverse(TreeNode node) { if (root == null) { return; } //preOrder print(root.value); traverse(root.left); //真正的遍历 //inOrder print(root.value); traverse(root.right); //真正的遍历 //postOrder print(root.value); }
真正的遍历就这两句话,不管是那种遍历顺序都是不变的,变的只是打印的顺序罢了。
这三种遍历都是深度优先遍历 DFS
,而层序遍历是广度优先遍历 BFS
。
DFS
和 BFS
都是图的基本遍历方式,我以后也会专门写一篇。
那咱们来看层序遍历 level order traversal
。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1MSSzsSF-1597109557049)(https://imgkr2.cn-bj.ufileos.com/cad35679-0c81-4112-950c-86c07369b5a2.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=TnZk7NTw66pp2BaiH6QLLtxxWbg%253D&Expires=1597102808)]
输出 5 7 3 1 4
.
参考 Leetcode 102 题。
也就是每一层按照从左到右的顺序遍历。
那么还有一种 Zigzag
的遍历方式,就是一行从左到右,下一行从右到左这样子。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eshtUJQr-1597109557053)(https://imgkr2.cn-bj.ufileos.com/8b6af38a-f269-4e0f-bf8f-3d46e4d6a0cc.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=erbbQdbHHPuWcXgq25C0aDN4hMQ%253D&Expires=1597102845)]
输出的就是 5 3 7 1 4
.
参考 Leetcode 103 题。
left/right/vertical/border view
,也就是求树的左视图、右视图、俯视图,是很是爱考的一类题,它们是什么意思呢?
好比对于这棵树,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p34wooea-1597109557058)(https://imgkr2.cn-bj.ufileos.com/ef39a70b-967b-43e4-83e7-088d20793055.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=UYhxr3jtQreLAChYSnTkVUhVXn4%253D&Expires=1597102944)]
左视图 left view
:
[5, 7, 9]
右视图 right view
:
[5, 3, 8]
这两个应该比较简单,在层序遍历的时候保留咱们须要的值就能够了。
固然还有其余方法,好比前序遍历能够作左视图,但不是那么的直观,由于你还要判断这个元素是不是当前层的第一个。你们有想法的能够在群里交流哟。(提示:能够再加一个变量
俯视图
这个视图比前两个稍微难一点,在北美面试中是很爱考的。
首先这个图中有一个变量叫 column
,根节点为 0,左孩子 - 1,右孩子 + 1。
俯视图指的是,从上往下看这棵树,把 column 相同的这些节点放在一个 list 里,从上往下放,而后按照 column 从小到大的顺序排出来。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-44PZs5WM-1597109557059)(https://imgkr2.cn-bj.ufileos.com/cabbffab-50a4-4822-93a5-411cc815e7ee.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=zCqjpB47J2Z6enDV7xwMS6rg1%252FE%253D&Expires=1597102976)]
因此对于这棵树,它的俯视图是:
[[7], [5, 9], [3], [8]]
这题就做为本文的思考题啦,不是很难,你们能够在评论区或者群里交流~
Border View
在讲完前三种视图以后,这个 border view
想必你们都能猜出来意思了。
就是求这棵树的“轮廓”。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WLhKAE8b-1597109557060)(https://imgkr2.cn-bj.ufileos.com/810525be-88b3-4872-aaf9-b8f0cc393d77.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=Z7t2bc0%252BiCanzNqknT7kp7gv0%252Bc%253D&Expires=1597103103)]
好比仍是这棵树,它的 border view
就是:
5, 7, 9, 8, 3
这题的大致思路不难,可是细节不少,并且不少条件可能就像我给的这样并无定义清楚,因此你须要和面试官不断的 clarify
不少细节。
普通的思路能够用
左视图 + 叶子结点 + 反着的右视图
来作,表面上来看须要作三遍遍历,可是其实一遍遍历就够了,由于我刚才说过,DFS 遍历时,哪一种遍历方式都是同样的,只是在不一样时间打印不一样节点罢了。
好了,以上就是本文的所有内容,若是喜欢,记得点赞哦~
8 月云自习打卡活动正在火热 🔥 进行中,喏 👇,天天你们都在学习打卡,具体的规则点这里查看,欢迎你的加入。
我是小齐,终身学习者,每晚 9 点,自习室里咱们不见不散 ❤️