二叉树理论基础
- 树的基本定义
树是由n个有限节点组成一个具有层次关系的集合
树具有的特点:
- 每个结点有零个或多个结点
- 没有父节点的结点为根结点
- 每一个非根结点只有一个父节点
- 每个结点及其后代结点整体上可以看做是一棵树,称为当前节点的父节点的一个子树
- 树的相关术语
结点的度:一个节点含有子树的个数
叶节点:度为0的结点称为叶节点,也叫终端节点
分支节点:度不为0的结点
结点的层次:从根节点开始,根节点的层次为1,根后的结点层次为2。。
节点的层序编号:将树种的结点,按照从上层到下层,同层从左到右的次序排成一个线性序列
树的度:树中结点的度的最大值
树的高度:树中结点的最大层次
森林:m个互不相交的树的集合,将一颗非空树的根节点删去,树就变成了一个森林;给森林增加一个统一的根节点,森林就变成了一棵树
孩子结点:一个结点的直接后续结点
双亲结点:一个结点的直接前驱
- 二叉树
二叉树的度不超过2
满二叉树:每一层的结点树都达到最大值,则这个二叉树就是满二叉树
完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的节点都集中在改成最左边的若干位置
• 二叉查找树的创建
插入put():
如果新结点的key小于当前结点的key,则继续找当前结点的左子结点
如果新结点的key大于当前结点的key,则继续找当前结点的右子结点
如果新结点的key等于当前结点的key,则树中已存在,替换value
查询get():
如果查询的key小于当前结点的key,则继续找到当前结点的左子结点
如果查询的key大于当前结点的key,则继续找到当前结点的右子结点
如果查询的key等于当前结点的key,则树中返回当前结点的value
删除delete():
- 找到被删除结点
- 找到被删除结点右子树中的最小节点minNode
- 删除右子结点的左子树称为最小节点minNode的左子树,让被删除的右子树称为最小结点minNode的右子树
- 让被删除结点的父节点指向最小结点minNode
• 二叉树的基础遍历(深度优先)
- 前序遍历
先访问结点,然后访问左子树,最后访问右子树
- 中序遍历
先访问左子树,中间访问根节点,最后访问右节点
- 后序遍历
先访问左子树,在访问右子树,最后访问根节点
- 层序遍历(广度优先)
从根节点开始,依次向下,获取每一层所有结点的值(从上到下,从左到右)
- 二叉树最大深度问题
给定一棵树,计算树的最大深度
一棵深度(按根节点深度为1)为k的二叉树最多可以有 2^k - 1 个节点
-
二叉树的定义
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this.val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; } }
二叉树的递归遍历
144. 二叉树的前序遍历
给你二叉树的根节点
root
,返回它节点值的 前序 **遍历。
输入:root = [1,null,2,3]
输出:[1,2,3]
前序遍历:中左右
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result=new ArrayList<>();
preorder(root,result);
return result;
}
public void preorder(TreeNode root,List<Integer> reslut){
if(root==null){
return;
}
reslut.add(root.val);
preorder(root.left,reslut);
preorder(root.right,reslut);
}
}
递归三要素:
- 确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
- 确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
- 确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
145. 二叉树的后序遍历
给你一棵二叉树的根节点
root
,返回其节点值的 后序遍历 。
输入:root = [1,null,2,3]
输出:[3,2,1]
后序遍历:左右中
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> reslut=new ArrayList<>();
postorder(root,reslut);
return reslut;
}
public void postorder(TreeNode root,List<Integer> reslut){
if(root==null){
return;
}
postorder(root.left,reslut);
postorder(root.right,reslut);
reslut.add(root.val);
}
}
94. 二叉树的中序遍历
给定一个二叉树的根节点
root
,返回 它的 中序 遍历
输入:root = [1,null,2,3]
输出:[1,3,2]
中序遍历左中右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> reslut=new ArrayList<>();
inorder(root,reslut);
return reslut;
}
public void inorder(TreeNode root,List<Integer> reslut){
if(root==null){
return;
}
inorder(root.left,reslut);
reslut.add(root.val);
inorder(root.right,reslut);
}
}
二叉树的迭代遍历
144. 二叉树的前序遍历
入栈顺序:中——右——左
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.right != null){
stack.push(node.right);
}
if (node.left != null){
stack.push(node.left);
}
}
return result;
}
}
145. 二叉树的后序遍历
后序遍历和前序遍历类似,入栈顺序:中——左——右,出栈顺序:中——右——左(反转即可)
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.pop();
result.add(node.val);
if (node.left != null){
stack.push(node.left);
}
if (node.right != null){
stack.push(node.right);
}
}
Collections.reverse(result);
return result;
}
}
94. 二叉树的中序遍历
入栈顺序:左——右
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
if (root == null){
return result;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while (cur != null || !stack.isEmpty()){
if (cur != null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
result.add(cur.val);
cur = cur.right;
}
}
return result;
}
}
二叉树的统一迭代(简单了解)
要处理的节点放入栈之后,紧接着放入一个空指针作为标记