目录
1. 基本概念
子树是不相交的;
除了根结点外,每个结点有且仅有一个父结点;
一颗N个结点的树有N-1条边。
结点的度:一个结点含有子树的个数称为该结点的度;
树的度:一棵树中,所有结点度的最大值称为树的度;
叶子结点或终端结点:度为0的结点称为叶结点;
双亲结点或父结点:若一个结点含有子结点,则称这个结点为其子结点的父结点;
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;
根结点:一棵树中,没有双亲结点的结点;
结点的层次:从根开始定义起,根为第一层,根的子结点为第二层,以此类推;
树的高度或深度:树中结点的最大层次。
树的应用:文件系统管理(目录和文件)
2. 二叉树(重点)
一棵二叉树是结点的一个有限集合,该集合:
- 或者为空
- 或者是由一个根节点加上两棵树别称为左子树和右子树的二叉树组成
二叉树不存在度大于2的节点;二叉树的子树有左右之分,次序不能颠倒,因此,二叉树是有序树
注意:对于任意的二叉树,都是由以下几种情况复合而成的:空树,只有根节点,只有左子树,只有右子树,左右子树均存在。
2.1 两种特殊的二叉树
1.满二叉树:一棵二叉树,如果每层的节点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且节点总数是2^k-1,则为满二叉树
2.完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点——对应时称之为完全二叉树(也可以说,是由上到下,由左到右一次引出节点的二叉树)
注意:满二叉树是一种特殊的完全二叉树
2.2 二叉树的性质
- 若规定根节点的层数为1,则一棵二叉树的第 i 层上最多有2^(i-1)个节点。
- 若规定只有根节点的二叉树的深度为1,则深度为K的二叉树的最大节点数是2^k-1。
- 对任何一棵二叉树,如果其叶结点个数为n0,度为2的非叶结点个数为n2,则有n0=n2+1。
- 一棵N个节点的树有N-1条边。
- n0表示产生不了边;n1表示产生n1条边;n2表示产生2*n2条边。
- 则有n1+2*n2=N-1;n0+n1+n2=N==>n0=n2+1
- 具有n个结点的完全二叉树的深度K为log2(n+1)向上取整
- 对于具有n个节点的完全二叉树,如果按照从上至下,从左至右的顺序对所有结点从0开始编号,则对于序号为i的节点有:
- 若i>0,双亲序号:(i-1)/2。(i=0,i为根结点编号,无双亲节点)
- 若2i+1<n,左孩子序号:2i+1,否则无左孩子。
- 若2i+2<n,右孩子序号:2i+2,否则无右孩子。
2.3 练习题
练习1:
练习2:
练习3:
2.4 二叉树的存储
二叉树的存储结构为:顺序存储和类似于链表的链式存储
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式。
练习1:
练习2:
练习3:
2.5 遍历的代码实现:
public void preOrder(TreeNode root) {//前序遍历
if (root == null) {
return;
}
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
//遍历思路
List<Character> list = new ArrayList<>();
public List<Character> preorderTraversal(TreeNode root) {
if (root == null) {
return list;
}
list.add(root.val);
preorderTraversal(root.left);
preorderTraversal(root.right);
return list;
}
//子问题思路
public List<Character> preorderTraversal2(TreeNode root) {
List<Character> list = new ArrayList<>();
if (root == null) {
return list;
}
list.add(root.val);
List<Character> leftTree = preorderTraversal2(root.left);
list.addAll(leftTree);
List<Character> rightTree = preorderTraversal2(root.right);
list.addAll(rightTree);
return list;
}
public void inOrder(TreeNode root) {//中序遍历
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
public void postOrder(TreeNode root) {//后序遍历
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val);
}
2.6 相关oj题
2.7 二叉树的基本操作
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
解法一:两条路径的交叉点,使用两个栈存放,多的那一个栈先弹出多余的元素,然后两个栈同时弹出元素,当两个元素相等时,即为共同祖先(巧妙)
解法二:递归(需要考虑多种情况)
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)