一、理论基础
1.1 二叉树的种类
满二叉树:一颗二叉树上只有度为0的节点和度为2的节点,并且度为0的节点都在同一层上
完全二叉树:若二叉树的深度为h,除第h层外,其它各层的节点数都达到最大值,第h层所有的节点都连续集中在最左边
完全二叉树判断方法:叶节点只能出现在最下层和次下层,并且最下面一层的节点都集中在最左边的若干位置
二叉搜索树:若左子树不空,则左子树上所有节点的值均小于它的根节点的值;若它的右子树不空,则右子树上所有节点的值大于它的根节点的值。它的左右子树也分别为二叉排序树
平衡二叉搜索树:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一颗平衡二叉树
1.2 二叉树的存储方式
链式存储:用指针
顺序存储:用数组
1.3 二叉树的遍历方式
1、深度优先遍历(DFS):先往深走,遇到叶子节点再往回走(前中后序遍历)
2、广度优先遍历(BFS):一层一层地去遍历(层次遍历)
前序遍历:中左右
中序遍历:左中右
后序遍历:左右中
1.4 二叉树的定义
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;
}
}
二、二叉树的遍历
2.1 深度优先遍历-前中后序
2.1.1 递归法
递归三要素:
1、确定递归函数的参数和返回值
2、确定终止条件
3、确定单层递归的逻辑
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
List<Integer> res;
public List<Integer> preorderTraversal(TreeNode root) {
//方法一:递归
res = new ArrayList<>();
preorder(root);
return res;
}
//注意返回值和参数
private void preorder(TreeNode root){
//终止条件:节点为空
if(root==null){
return;
}
//前序:中左右
//单层递归的逻辑
res.add(root.val);
preorder(root.left);
preorder(root.right);
}
}
2.1.2 迭代法
利用栈来实现(先进后出LIFO)
前序:中左右
根据栈先进后出的性质,出来时是左右,则进栈时应该是右左
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
//方法二:迭代法
//前序:中左右
//无论怎样,中间的节点都是先拎出来处理的,而根据栈先入后出的特点,要想出来后是中左右,进去的时候就应该是中右左
Stack<TreeNode> stack = new Stack<>();
List<Integer> res = new ArrayList<>();
if(root==null){
return res;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode tmpNode = stack.pop();
res.add(tmpNode.val);
if(tmpNode.right!=null){
stack.push(tmpNode.right);
}
if(tmpNode.left!=null){
stack.push(tmpNode.left);
}
}
return res;
}
}
后序其实就是在前序的基础上修改
后序:左右中
翻转过来就是中右左,和前序的区别就是左右换个顺序
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
//后序:左右中
//相当于先求 中右左,就是前序的左右换位置
//最后再翻转
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root==null){
return res;
}
stack.push(root);
while(!stack.isEmpty()){
TreeNode tmpNode = stack.pop();
res.add(tmpNode.val);
if(tmpNode.left!=null){
stack.push(tmpNode.left);
}
if(tmpNode.right!=null){
stack.push(tmpNode.right);
}
}
//对list集合进行逆序,使用Collections.reverse()方法
Collections.reverse(res);
return res;
}
}
中序遍历使用迭代法与前后序不同的原因在于,此时访问的节点和要处理的节点不是同一个
先不断向左找到要访问的节点,再通过栈去取出要处理的节点
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
//方法二:迭代法
//与前后序思路不同
List<Integer> res = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root==null){
return res;
}
TreeNode cur = root;
while(cur!=null || !stack.isEmpty()){
if(cur!=null){
stack.push(cur);
cur = cur.left;
}else{
cur = stack.pop();
res.add(cur.val);
cur = cur.right;
}
}
return res;
}
}
2.2 广度优先遍历-层序遍历
利用队列(先进先出)来实现层序遍历
三、求二叉树的属性
3.1 二叉树:是否对称
方法:递归【后序】
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return compare(root.left,root.right);
}
private boolean compare(TreeNode left,TreeNode right){
if(left==null && right!=null){
return false;
}
if(left==null || right==null){
return false;
}
if(left.val!=right.val){
return false;
}
//对比外侧
boolean out = compare(left.left,right.right);
//对比内侧
boolean in = compare(left.right,right.left);
//均要true才true
return out&∈
}
}
3.2 二叉树:最大/小深度
方法一:迭代法(不做详细说明,利用队列实现,和前面迭代大同小异)
方法二:递归法【后序】
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
if(root==null){
return 0;
}
int left = maxDepth(root.left);
int right =maxDepth(root.right);
return Math.max(left,right)+1;
}
}
最小深度:从根节点到最近叶子节点的最短路径上的节点数量
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
if(root==null){
return 0;
}
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
if(root.left==null){
return rightDepth+1;
}
if(root.right==null){
return leftDepth+1;
}
//左右节点均不为空
return Math.min(leftDepth,rightDepth)+1;
}
}
3.3 二叉树:求有多少个节点
迭代法:略
递归法:
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public int countNodes(TreeNode root) {
//递归法
if(root==null){
return 0;
}
int left = countNodes(root.left);
int right = countNodes(root.right);
return left+right+1;
}
}
3.4 二叉树:是否平衡
平衡二叉树:是指该树所有节点的左右子树的深度相差不超过 1
本题使用迭代法会十分繁琐,效率也低,故使用递归法【后序】
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public boolean isBalanced(TreeNode root) {
return getHeight(root)!=-1;
}
private int getHeight(TreeNode root){
if(root==null){
return 0;
}
//先判断是否满足平衡条件,不满足直接返回-1,无需做后面的计算
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
if(leftHeight==-1 || rightHeight==-1){
return -1;
}
if(Math.abs(leftHeight-rightHeight)>1){
return -1;
}
//返回树的高度
return Math.max(leftHeight,rightHeight)+1;
}
}
3.5 找所有的路径
递归【前序】+回溯
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
List<String> res;
List<TreeNode> paths;
public List<String> binaryTreePaths(TreeNode root) {
//递归+回溯
res = new ArrayList<>();
paths = new ArrayList<>();
getPaths(root);
return res;
}
private void getPaths(TreeNode root){
if(root==null){
return;
}
//前序遍历
paths.add(root);
//如果当前是叶子节点
if(root.left==null && root.right==null){
StringBuilder sb = new StringBuilder();
for(int i = 0;i<paths.size()-1;i++){
sb.append(paths.get(i).val).append("->");
}
sb.append(paths.get(paths.size()-1).val);
res.add(sb.toString());
}
if(root.left!=null){
getPaths(root.left);
paths.remove(paths.size()-1);
}
if(root.right!=null){
getPaths(root.right);
paths.remove(paths.size()-1);
}
}
}
3.6 二叉树:求左叶子之和
递归法
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
//注意:本题容易遗漏的信息-叶子节点!
int sum;
public int sumOfLeftLeaves(TreeNode root) {
sum = 0;
getSum(root);
return sum;
}
private void getSum(TreeNode root){
if(root==null){
return;
}
if(root.left!=null){
if(root.left.left==null && root.left.right==null){
sum += root.left.val;
}
}
getSum(root.left);
getSum(root.right);
}
}
3.7 二叉树:求左下角的值
迭代略
3.8 二叉树:求路径总和
递归:顺序无所谓,递归函数返回值为bool类型是为了搜索一条边,没有返回值是搜索整棵树
有返回值:找到一个true就返回,而不用搜整棵树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
return caculateSum(root,targetSum);
}
private boolean caculateSum(TreeNode root,int targetSum){
//前序遍历
if(root==null){
return false;
}
targetSum -= root.val;
if(root.left==null && root.right==null){
if(targetSum==0){
return true;
}
return false;
}
return caculateSum(root.left,targetSum) || caculateSum(root.right,targetSum);
}
}
四、二叉树的修改与构造
4.1 翻转二叉树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
//递归
if(root==null){
return root;
}
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
invertTree(root.left);
invertTree(root.right);
return root;
}
}
4.2 构造二叉树
4.2.1 前序与中序构造
注意点:
1、记录:索引、创建节点、左边长度
2、左开右闭
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
Map<Integer,Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
map = new HashMap<>();
for(int i = 0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return getRoot(preorder,0,preorder.length,inorder,0,inorder.length);
}
private TreeNode getRoot(int[] preorder,int preBegin,int preEnd,int[] inorder,int inBegin,int inEnd){
//左闭右开
if(preBegin>=preEnd || inBegin>=inEnd){
return null;
}
//记录父节点的索引位置
int nodeIndex = map.get(preorder[preBegin]);
//创建节点
TreeNode root = new TreeNode(inorder[nodeIndex]);
//记录左边的长度
int lenOfLeft = nodeIndex-inBegin;
root.left = getRoot(preorder,preBegin+1,preBegin+1+lenOfLeft,inorder,inBegin,nodeIndex);
root.right = getRoot(preorder,preBegin+1+lenOfLeft,preEnd,inorder,nodeIndex+1,inEnd);
return root;
}
}
4.2.2 中序与后序构造
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
Map<Integer,Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>();
for(int i = 0;i<inorder.length;i++){
map.put(inorder[i],i);
}
return getRoot(inorder,0,inorder.length,postorder,0,postorder.length);
}
private TreeNode getRoot(int[] inorder,int inBegin,int inEnd, int[] postorder,int postBegin,int postEnd){
if(inBegin>=inEnd || postBegin>=postEnd){
return null;
}
int nodeIndex = map.get(postorder[postEnd-1]);
TreeNode root = new TreeNode(inorder[nodeIndex]);
int lenOfLeft = nodeIndex-inBegin;
root.left = getRoot(inorder,inBegin,nodeIndex,postorder,postBegin,postBegin+lenOfLeft);
root.right = getRoot(inorder,nodeIndex+1,inEnd,postorder,postBegin+lenOfLeft,postEnd-1);
return root;
}
}
4.3 构造最大的二叉树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
Map<Integer,Integer> map;
public TreeNode constructMaximumBinaryTree(int[] nums) {
map = new HashMap<>();
for(int i = 0;i<nums.length;i++){
map.put(nums[i],i);
}
return getRoot(nums,0,nums.length);
}
private TreeNode getRoot(int[] nums,int begin,int end){
if(begin>=end){
return null;
}
int max = nums[begin];
for(int i = begin;i<end;i++){
max = Math.max(max,nums[i]);
}
int rootIndex = map.get(max);
TreeNode root = new TreeNode(max);
root.left = getRoot(nums,begin,rootIndex);
root.right = getRoot(nums,rootIndex+1,end);
return root;
}
}
4.4 合并两个二叉树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
if(root1==null && root2==null){
return null;
}
if(root1==null && root2!=null){
return root2;
}
if(root1!=null && root2==null){
return root1;
}
//都不为null
TreeNode root = new TreeNode(root1.val+root2.val);
root.left = mergeTrees(root1.left,root2.left);
root.right = mergeTrees(root1.right,root2.right);
return root;
}
}
五、求二叉搜索树的属性
5.1 二叉搜索树中的搜索
迭代法略啦,重点介绍一下递归法
二叉树的递归法都是有方向的
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode searchBST(TreeNode root, int val) {
//递归法
if(root==null || root.val==val){
return root;
}
//目标数比节点的数小,则往左子树找,反之找右子树
if(root.val>val){
return searchBST(root.left,val);
}else{
return searchBST(root.right,val);
}
}
}
5.2 是不是二叉搜索树
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return validBST(Long.MIN_VALUE,Long.MAX_VALUE,root);
}
private boolean validBST(long lower,long upper,TreeNode root){
if(root==null){
return true;
}
//注意:等于也不行
if(root.val<=lower || root.val>=upper){
return false;
}
return validBST(lower,root.val,root.left) && validBST(root.val,upper,root.right);
}
}
5.3 求二叉搜索树的最小绝对差
迭代法略
递归法:注意这是一个二叉搜索树,可以看作一个有序数组,求最小差值,那只有可能在两相邻节点
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
int res;
TreeNode pre;
public int getMinimumDifference(TreeNode root) {
res = Integer.MAX_VALUE;
if(root==null){
return 0;
}
traversal(root);
return res;
}
private void traversal(TreeNode root){
if(root==null){
return;
}
traversal(root.left);
if(pre!=null){
res = Math.min(res,Math.abs(pre.val-root.val));
}
pre = root;
traversal(root.right);
}
}
5.4 求二叉搜索树的众数
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
int maxCount;
int count;
List<Integer> list;
TreeNode pre;
public int[] findMode(TreeNode root) {
maxCount = 0;
count = 0;
pre = null;
list = new ArrayList<>();
findMode1(root);
int[] res = new int[list.size()];
for(int i = 0;i<res.length;i++){
res[i] = list.get(i);
}
return res;
}
private void findMode1(TreeNode root){
if(root==null){
return;
}
findMode1(root.left);
//注意:pre==null不可漏,若限定大条件pre!=null,那么pre==null的情况也会被忽略
if(pre==null || pre.val!=root.val){
count=1;
}else{
count++;
}
if(count>maxCount){
maxCount = count;
list.clear();
list.add(root.val);
}else if(count==maxCount){
list.add(root.val);
}
pre = root;
findMode1(root.right);
}
}
5.5 二叉搜索树转成累加树
核心:按右中左顺序遍历
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
int sum;
public TreeNode convertBST(TreeNode root) {
sum = 0;
traversal(root);
return root;
}
private void traversal(TreeNode root){
//右中左
if(root==null){
return;
}
traversal(root.right);
sum += root.val;
root.val = sum;
traversal(root.left);
}
}
六、 二叉树公共祖先问题
6.1 二叉树的公共祖先问题
如果递归遍历遇到q,就将q返回,遇到p 就将p返回,那么如果 左右子树的返回值都不为空,说明此时的中节点,一定是q 和p 的最近祖先
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null || root==p || root==q){
return root;
}
//祖先:后序遍历
TreeNode left = lowestCommonAncestor(root.left,p,q);
TreeNode right = lowestCommonAncestor(root.right,p,q);
if(left==null && right==null){
return null;
}else if(left!=null && right==null){
return left;
}else if(left==null && right!=null){
return right;
}
return root;
}
}
6.2 二叉搜索树的公共祖先问题
也可以按一般二叉树去解决,但既然有二叉搜索树的特性,别浪费噜
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//既然是二叉搜索树,那就利用好它右大左小的性质
//递归法
if(root.val>p.val && root.val>q.val){
return lowestCommonAncestor(root.left,p,q);
}else if(root.val<p.val && root.val<q.val){
return lowestCommonAncestor(root.right,p,q);
}
return root;
}
}
七、 二叉搜索树的修改与构造
7.1 二叉搜索树中的插入操作
多种方式都可,那么可以不用考虑复杂的改变树的构造
直接遍历二叉树,找到空节点,插入即可
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
//遍历二叉树,找到空节点(末尾节点)插入即可
if(root==null){
return new TreeNode(val);
}
if(root.val>val){
//小,往左走
root.left = insertIntoBST(root.left,val);
}else if(root.val<val){
//大,往右走
root.right = insertIntoBST(root.right,val);
}
return root;
}
}
7.2 二叉搜索树中的删除操作
步骤:1、找节点
2、删除节点
情况分析:①找不到节点:返回root
②找到节点:I.该节点“缺一边”:直接返回另一半边树
II.节点左右子树均不为null:将左子树搬到右子树的最左侧(原理:比小的还小,那一定比大的小)
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
//1、找节点(前序)
//2、删除节点
if(root==null){
return root;
}
//找到节点了
if(root.val==key){
if(root.left==null){
return root.right;
}else if(root.right==null){
return root.left;
}
//均不为空
//左子树移到右子树最左的后面(比小的还小,那一定比大的小)
TreeNode cur = root.right;//先找到右子树的最左节点
while(cur.left!=null){
cur = cur.left;
}
cur.left = root.left;//为右子树最左节点的后面赋值,把左子树迁移过去
return root.right;//注意:此处要把root删了,把左子树已经转移到右子树最左侧了,直接返回右子树即可
}
//在处理递归调用时,应该将结果返回给父调用,而不是丢弃它
if(root.val>key){
//小,往左找
root.left = deleteNode(root.left,key);
}else if(root.val<key){
//大,往右找
root.right = deleteNode(root.right,key);
}
return root;
}
}
7.3 修剪二叉搜索树
步骤:1、找需要修剪的节点
2、删除节点
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
//左闭右闭
//前序
if(root==null){
return root;
}
//找到了要删除的节点
if(root.val > high ){
//节点都大了,那右子树更是不能要了,所以往左走
return trimBST(root.left,low,high);
}else if(root.val < low){
//同理,节点小了,往右走
return trimBST(root.right,low,high);
}
//没找到,继续递归排查
root.left = trimBST(root.left,low,high);
root.right = trimBST(root.right,low,high);
return root;
}
}
7.4 构造二叉搜索树
注意特殊的写法以防数组越界
/**
* Definition for a binary tree node.
* 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;
* }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
//左闭右开
return getRoot(nums,0,nums.length);
}
private TreeNode getRoot(int[] nums,int begin,int end){
//别漏了最开始验证区间合理的条件!!!
if(begin>=end){
return null;
}
//不使用(begin+end)/2:防止数组越界
int nodeIndex = begin+(end-begin)/2;
TreeNode root = new TreeNode(nums[nodeIndex]);
//注意:升序排列,故index右边是左子树,index左边是右子树
root.left = getRoot(nums,begin,nodeIndex);
root.right = getRoot(nums,nodeIndex+1,end);
return root;
}
}
八、 总结
1、二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,先构造中节点!
2、求不同二叉树的属性,一般用后序,但还是要具体问题具体分析!
3、求二叉搜索树的属性,用前序,不然白瞎有序性了!