树
属性
可以递归定义,调用自己,孩子又是一棵树的根节点。
具有层级结构
一对多
Node结点
root根
Children孩子
Parent双亲
Sibling兄弟 有同一个双亲
leaf 叶子 没有孩子
结点的层次(level):从根结点算起,根为第一层,它的孩子为第二层……
结点的度(degree):结点拥有的子树数
树的度:一棵树中最大的结点度数
有n个结点node,那么有n-1个边edge
深度 Depth 从根到x的edge的数目,根的Depth为0,国内根的深度为1
高度Height 从x到叶子结点的最多边的数目,国内高度要加1
树的高度是根结点的高度
结点的度(degree):结点拥有的子树数
应用
存储天然具备层级结构的数据
文件和文件夹
组织数据
让集合快速查找 删除等
Tire树 动态的拼写检查
network Routing algorithm网络路由算法
二叉树Binary Tree
一个最多有两个孩子
分类
严格二叉树
每个结点有0或两个孩子
完全二叉树
除了最后一层都填满,并且最后一层的结点若没有完全填充,那么向左对齐
满二叉树Perfect Binary Tree
最后一层也满,所有的都满,是完全二叉树的特例
存储可修改的集合
用数目数据结构来存储可修改的集合
这样要求快速查找,插入,删除
array
end标记结尾,
search 从开头到结尾,故O(n)
insert 若插入末尾 O(1),若满,O(n)
remove O(n)
Linked LIst
搜索O(n)
头部插入O(1)
删除O(n)
Array(sortrd)
查找的话,O(n)时间复杂度太大。如果排序了
的话,可以使用二分查找。所以在插入和删除的时候,我们就要对这个数组排好序。排序后的数组查找很方便,但是插入和删除依旧要O(n)
Binary Search Tree(balanced)
a balanced tree (对于任何结点,左右子树的高度差不大于1)。二叉搜索树可以不平衡
对于根结点,所有(故下图16大于15,不是BST)左子树的结点值都比该结点上的值小或等于,右子树上的结点值比该节点的值大。并且每一个子树又分别是二叉搜索树
递归构建二叉搜索树
判断该数字在二叉树中是否存在
在二叉搜索树中找到最大值和最小值
迭代版本(循环)
递归版本
判断是否为二叉搜索树
一种根据定义直接想出的办法,直接判断左子树的所有数是否小于等于根结点,右子树的所有数大于根结点以及判断每一个子树是否都是二叉搜索数
先编写判断子树的所有数小于等于value的函数
判断子树的所有数大于value的函数
上面的代码的时间复杂度是O(n^2)
下面介绍时间复杂度为O(n)的代码
对每个结点只访问一次
从上往下看,对于每一个结点来说,除了要满足上一个结点的数值范围要求,而且如果该点还满足本身这个结点位于上一个结点的左(小于),右(大于)的要求,那么ok
如果从上往下看,所有的结点都满足上面的条件
还有一种办法,如果是二叉搜索树,那么中序遍历得到的顺序是排序的
性质
在非空二叉树中,第i层上至多有2i-1个结点(i≧1)
性质2:深度为k的二叉树至多有2k-1个结点(k≧1)( 2 0+21+ …+2k-1=2k-1 )
对任何一棵二叉树,若其叶子结点数为n0,度为2的结点数为n2,则n0=n2+1
n个结点的完全二叉树深度为:㏒以二为底n向下取整+1。
实现
dynamically
最常见的实现,结点三个域,左孩子,右孩子,数据域。
arrays数组
对于完全二叉树上编号为i的结点元素存储在一维数组的下标值为i-1的分量中。
对于一般的二叉树,将其每个结点与完全二叉树上的结点相对照,存储在一维数组中。数组下标为i,对应二叉树结点的标号为i+1(国内,国外对应的还是i),那么左孩子的索引是2i+1,右孩子的索引是2i+2,辅助记忆(记忆根和左右结点的关系
国外版
操作
找到二叉树的高度
递归计算
伪代码
运行时间 On
遍历
二叉树的遍历
访问树所有结点,每个制备访问一次
更具访问顺序,分为两类
广度优先,深度优先
Breadth-first(BFS)广度优先搜索
先遍历同一层次的结点,从左往右
广度优先
层次遍历
层次遍历是说逐层遍历。
Level-order Traversal
如上图中箭头所指的顺序,顾名思义,从上往下,从左往右,也就是先从左往右读取第一层,再从左往右第二层。
当前指向根结点F,我们下一个要遍历的是D,但是如果我们把指针移动到F的位置,由于结点没有记录它的双亲F,因此我们会丢失J的信息,找不到J了。
因此在读取F的时候,就应该记录下F的孩子结点的信息以便我们找到。对于D,我们同样需要记录它的孩子结点的信息,先记录的孩子结点信息会被先被读取,先进先出,因此我们考虑队列。
要考虑树为空的情况
获得一个结点,访问并让左右孩子入队,让其出队。
对于每个结点都如此操作,因此时间复杂度为O(n)
空间复杂度,
这样的树,始终只需要常数空间O(1)
上图的二叉树需要在需要空间最多的时候,是最后一层的数目,也就是结点总数(n+1)/2,空间复杂度为O(n)
对于平均的场景,空间复杂度为O(n)
Depth-first(DFS)深度优先搜索
左子树完成才可以来到右 子树
由于默认左子树先被右子树遍历
按照根节点被遍历的顺序
有 先序遍历中序遍历和后序遍历
如图
先序遍历Preorder
中序遍历Inorder
递归带来的内存取决于树的最大高度
对于二叉搜索树,也就是对于每个结点,左边的值比较小,而右边的值比较大,那么如果中序遍历的话,会得到一个排序的列表
后序遍历
时间复杂度,因为对每一个结点访问一次,因此时间复杂度是O(n)