二叉树专项
二叉树的基础知识
一.二叉树的种类
满二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
完全二叉树
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点是从左到右连续的。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
优先级队列其实是一个堆,堆就是一棵完全二叉树,同时保证父子节点的顺序关系。
二叉搜索树
二叉搜索树是一个有序树。
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
平衡二叉搜索树(AVL树)
它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二.二叉树的存储方式
二叉树可以链式存储,也可以顺序存储。
那么链式存储方式就用指针, 顺序存储的方式就是用数组。
用数组来存储二叉树如何遍历的呢?
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
三.二叉树的遍历方式
二叉树中可以用递归来解决的一般都可以用迭代解决
二叉树主要有两种遍历方式:
1.深度优先遍历:先往深走,遇到叶子节点再往回走。
深度优先遍历
前序遍历(递归法,迭代法):中左右
中序遍历(递归法,迭代法):左中右
后序遍历(递归法,迭代法):左右中
2.广度优先遍历:一层一层的去遍历。
层次遍历(迭代法)
举例:快速排序就是二叉树的前序遍历,先把一个元素排好序,再把元素左半边排好序,在将元素的右半边排好序
归并排序就是二叉树的后序遍历,先把元素左半边排好序,再将元素的右半边排序,最后将二者合起来
四.二叉树的定义
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;
}
}
五.二叉树解体的思维模式:
1.遍历的思维模式:可以通过遍历一遍二叉树得到答案的,用一个traverse函数配合外部变量实现 该思路对应着回溯的核心框架
2.分解的思维模式:定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案 该思路对应动态规划核心框架
二叉树解题总纲:
1.这题能不能用遍历的思维模式解决
2.这题能不能用分解问题的思维模式解决
二叉树的遍历框架
前中后序是遍历二叉树过程中处理每一个节点的三个特殊时间点即前序位置,后序位置和中序位置
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
traverse(root.left);
// 中序位置
traverse(root.right);
// 后序位置
}
//traverse函数就是一个能够遍历二叉树所有节点的一个函数
//单链表和数组的遍历可以是迭代也可以是递归,二叉树这种结果也就是二叉链表
//由于没法写成迭代的形式,所以一般二叉树的遍历框架都是递归
//前序位置的代码在刚刚进入一个二叉树节点时执行 这说明前序位置的代码只能从函数参数中获取父节点传来的数据
//后序位置的代码在即将要离开一个二叉树节点的时候执行
//后续位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据
//中序位置的代码在一个二叉树左子树都遍历完,即将开始遍历右子树的时候执行
//每个节点都有唯一属于自己的前中后序位置