数据结构——二叉树

1. 树形结构

1. 概念

树是⼀种⾮线性的数据结构,它是由n(n>=0)个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,⽽叶朝下的。它具有以下的特点:
有⼀个特殊的结点,称为根结点,根结点没有前驱结点
除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每⼀个集合Ti
(1 <= i <= m) ⼜是⼀棵与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以有0个或多个后继
树是递归定义的
注意:树形结构中,⼦树之间不能有交集,否则就不是树形结构
结点的度:⼀个结点含有⼦树的个数称为该结点的度; 如上图:A的度为6
树的度:⼀棵树中,所有结点度的最⼤值称为树的度; 如上图:树的度为6
叶⼦结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点
双亲结点或⽗结点:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点; 如上图:A是B的⽗结点
孩⼦结点或⼦结点:⼀个结点含有的⼦树的根结点称为该结点的⼦结点; 如上图:B是A的孩⼦结点
根结点:⼀棵树中,没有双亲结点的结点;如上图:A
结点的层次:从根开始定义起,根为第1层,根的⼦结点为第2层,以此类推
树的⾼度或深度:树中结点的最⼤层次; 如上图:树的⾼度为4
⾮终端结点或分⽀结点:度不为0的结点; 如上图:D、E、F、G...等节点为分⽀结点
兄弟结点:具有相同⽗结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
堂兄弟结点:双亲在同⼀层的结点互为堂兄弟;如上图:H、I互为兄弟结点
结点的祖先:从根到该结点所经分⽀上的所有结点;如上图:A是所有结点的祖先
⼦孙:以某结点为根的⼦树中任⼀结点都称为该结点的⼦孙。如上图:所有结点都是A的⼦孙
森林:由m(m>=0)棵互不相交的树组成的集合称为森林

2. 树的表⽰形式

双亲表⽰法,孩⼦表⽰法、孩⼦双亲表⽰法、孩⼦兄弟表⽰法
//孩⼦兄弟表⽰法
class Node{

    int val;//存储树节点的数据
    Node firstChild;//指向第一个孩子
    Node nextBrother;//指向兄弟节点
}

2. 二叉树

1. 概念

⼀棵⼆叉树是结点的⼀个有限集合,该集合:
1. 或者为空
2. 或者是由⼀个根节点加上两棵别称为左⼦树和右⼦树的⼆叉树组成
注意:对于任意的⼆叉树都是由以下⼏种情况复合⽽成
1. ⼆叉树不存在度⼤于2的结点
2. ⼆叉树的⼦树有左右之分,次序不能颠倒,因此⼆叉树是有序树

2 两种特殊的⼆叉树

1. 满⼆叉树: ⼀棵⼆叉树,如果每层的结点数都达到最⼤值,则这棵⼆叉树就是满⼆叉树。也就是说,如果⼀棵⼆叉树的层数为K,且结点总数是^{​{_{2}}^{K}}-1 ,则它就是满⼆叉树。
2. 完全⼆叉树: 完全⼆叉树是效率很⾼的数据结构,完全⼆叉树是由满⼆叉树⽽引出来的。对于深度为K的,有n个结点的⼆叉树,当且仅当其每⼀个结点都与深度为K的满⼆叉树中编号从0⾄n-1的结点⼀ 对应时称之为完全⼆叉树。 要注意的是满⼆叉树是⼀种特殊的完全⼆叉树

3. ⼆叉树的性质

1. 若规定根结点的层数为1,则⼀棵⾮空⼆叉树的第i层上最多有 2^{i-1} (i>0)个结点
2. 若规定只有根结点的⼆叉树的深度为1,则深度为K的⼆叉树的最⼤结点数是 2^{k}-1 (k>=0)
3. 对任何⼀棵⼆叉树, 如果其叶结点个数为 n0, 度为2的⾮叶结点个数为 n2,则有n0=n2+1
4. 当二叉树的总结点个数为偶数时,n1=1;
    当二叉树的总结点个数为奇数时,n1=0。(n1即节点有一条边)
5. 具有n个结点的完全⼆叉树的深度k为\log_{2}(n-1)向上取整
6. 对于具有n个结点的完全⼆叉树,如果按照从上⾄下从左⾄右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,⽆双亲结点
若2i+1<n,左孩⼦序号:2i+1,否则⽆左孩⼦
若2i+2<n,右孩⼦序号:2i+2,否则⽆右孩⼦

4. ⼆叉树的存储

⼆叉树的存储结构分为:顺序存储类似于链表的链式存储
⼆叉树的链式存储是通过⼀个⼀个的节点引⽤起来的,常⻅的表⽰⽅式有⼆叉和三叉表⽰⽅式,
/ 孩⼦表⽰法
class Node {
    int val; // 数据域
    Node left; // 左孩⼦的引⽤,常常代表左孩⼦为根的整棵左⼦树
    Node right; // 右孩⼦的引⽤,常常代表右孩⼦为根的整棵右⼦树
}

// 孩⼦双亲表⽰法
class Node {
    int val; // 数据域
    Node left; // 左孩⼦的引⽤,常常代表左孩⼦为根的整棵左⼦树
    Node right; // 右孩⼦的引⽤,常常代表右孩⼦为根的整棵右⼦树
    Node parent; // 当前节点的根节点
}

5.  ⼆叉树遍历

所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做⼀次且仅做⼀次访问。访问结点所做的操作依赖于具体的应⽤问题(⽐如:打印节点内容、节点内容加1)。

 层序遍历
层序遍历就是从所在⼆叉树的根节点出发,⾸先访问第⼀层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,⾃上⽽下,⾃左⾄右逐层访问树的结点的过程就是层序遍历。
NLR:前序遍历(Preorder Traversal 亦称先序遍历)⸺访问根结点--->根的左⼦树--->根的右⼦树。(根左右
LNR:中序遍历(Inorder Traversal)⸺根的左⼦树--->根节点--->根的右⼦树。(左根右
LRN:后序遍历(Postorder Traversal)⸺根的左⼦树--->根的右⼦树--->根节点。(左右根
// 前序遍历
void preOrder(Node root);
// 中序遍历
void inOrder(Node root);
// 后序遍历
void postOrder(Node root);

前序遍历结果:1 2 3 4 5 6
中序遍历结果:3 2 1 5 4 6
后序遍历结果:3 2 5 6 4 1
1.  已知前序遍历和中序遍历,求后序遍历

步骤

  1. 前序遍历的第一个结点是根结点。

  2. 在中序遍历中找到根结点的位置,根结点左侧是左子树的中序遍历,右侧是右子树的中序遍历。

  3. 根据左子树和右子树的结点数量,在前序遍历中划分左子树和右子树的前序遍历

  4. 递归处理左子树和右子树。

2. 已知中序遍历和后序遍历,求前序遍历

  • 步骤

    1. 后序遍历的最后一个结点是根结点。

    2. 在中序遍历中找到根结点的位置,根结点左侧是左子树的中序遍历,右侧是右子树的中序遍历。

    3. 根据左子树和右子树的结点数量,在后序遍历中划分左子树和右子树的后序遍历。

    4. 递归处理左子树和右子树。

3. 已知前序遍历和后序遍历,无法唯一确定中序遍历

  • 只有在二叉树是满二叉树真二叉树(每个结点都有 0 或 2 个孩子)时,才能唯一确定中序遍历。

例题

100. 相同的树 - 力扣(LeetCode)

572. 另一棵树的子树 - 力扣(LeetCode)

101. 对称二叉树 - 力扣(LeetCode)

110. 平衡二叉树 - 力扣(LeetCode)(绝对值<1&&左右树平衡)

题解 | 二叉树的构建及遍历_牛客网   

102. 二叉树的层序遍历 - 力扣(LeetCode)

226. 翻转二叉树 - 力扣(LeetCode)

958. 二叉树的完全性检验 - 力扣(LeetCode)

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值