目录
二叉树的一些概念
1. 节点的度:一个节点含有的子树的个数称为该节点的度;
2. 树的度:一棵树中,最大的节点的度称为树的度;
3. 叶子节点或终端节点:度为0的节点称为叶节点;
4. 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
5. 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
6. 根结点:一棵树中,没有双亲结点的结点;
7. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
8. 树的高度或深度:树中节点的最大层次;
一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉
树组成。
二叉树的特点:
每个结点最多有两棵子树,即二叉树不存在度大于 2 的结点。
二叉树的子树有左右之分,其子树的次序不能颠倒,因此二叉树是有序树
满二叉树**:** 一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果
一个二叉树的层数为**K**,且结点总数是 2^k-1,则它就是满二叉树。
完全二叉树**:** 除了最后一层,都满;最后一层从左至右排列,中间无空
#### 2n个节点的完全二叉树只有一个度为1的节点,则叶子节点数为n
#### 奇数个节点的完全二叉树没有度为1的节点
二叉树的遍历方式
前序遍历 -> 根 - 左 - 右(进入节点前的位置)
```java
/**
* 递归实现前序遍历
* @param root
*/
public void preOrder(TreeNode1 root) {
//边界条件
if (root == null) {
return;
}
System.out.println(root.val);
preOrder(root.left);
preOrder(root.right);
}
```
中序遍历 -> 左 - 根 - 右
```java
public void inOrder(TreeNode1 root) {
//边界条件
if (root == null) {
return;
}
inOrder(root.left);
System.out.println(root.val);
inOrder(root.right);
}
```
后序遍历 -> 左 - 右 - 根(离开节点后的位置)
```java
public void postOrder(TreeNode1 root) {
//边界条件
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.println(root.val);
}
```
二叉树前中后序遍历迭代法
```java
// 前序遍历顺序:中-左-右,入栈顺序:中-右-左
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;
}
}
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
ret.add(cur.val);
cur = cur.left;
}
TreeNode top = stack.pop();
cur = top.right;
}
return ret;
}
}
// 中序遍历顺序: 左-中-右 入栈顺序: 左-右
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;
}
}
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> ret = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(cur != null || !stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.pop();
ret.add(top.val);
cur = top.right;
}
return ret;
}
}
// 后序遍历顺序 左-右-中 入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
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;
}
}
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
List<Integer> ret = new ArrayList<>();
TreeNode prev = null;
while (cur != null || !stack.isEmpty()) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
TreeNode top = stack.peek();
//如果当前节点的右子树打印过,zh
if (top.right == null || top.right == prev) {
stack.pop();
ret.sdd(top.val);
prev = top;//记录一下最近打印的节点
} else {
cur = cur.right;
}
}
return ret;
}
```
二叉树的节点个数
```java
/**
* 求二叉树的节点个数
* @param root
* @return
*/
int count = 0;
public void size(TreeNode1 root) {
if (root == null) {
return;
}
count++;
size(root.left);
size(root.right);
}
public int size1(TreeNode1 root) {
if (root == null) {
return 0;
}
return size1(root.left)+size1(root.right)+1;
}
```
二叉树的叶子节点数
```java
int leafCount = 0;
public void sizeOfLeaves(TreeNode1 root) {
if (root == null) {
return;
}
if (root.right == null && root.left == null) {
leafCount++;
}
sizeOfLeaves(root.left);
sizeOfLeaves(root.right);
}
public int sizeOfLeaves1(TreeNode1 root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return sizeOfLeaves1(root.left)+sizeOfLeaves1(root.right);
}
```
第K层的节点个数
```java
/**
* 获取第K层节点的个数
* @param root
* @return
*/
public int leavesOfKthLevel(TreeNode1 root,int k) {
if (root == null || k <= 0) {
return 0;
}
if (k == 1) {
return 1;
}
return leavesOfKthLevel(root.left,k-1) + leavesOfKthLevel(root.right,k-1);
}
```
二叉树的深度
```java
/**
* 求二叉树的深度
* @param root
* @return
*/
public int depth(TreeNode1 root) {
if (root == null) {
return 0;
}
int leftDepth = depth(root.left);
int rightDepth = depth(root.right);
return 1+ Math.max(leftDepth,rightDepth);
}
```
在二叉树中查找val节点
```java
public TreeNode1 find(TreeNode1 root,char val) {
if (root == null) {
return null;
}
if (root.val == val) {
return root;
}
TreeNode1 ret = find(root.left,val);
if (ret != null) {
return ret;
}
ret = find(root.right,val);
if (ret != null) {
return ret;
}
return null;
}
```
判断是否为完全二叉树
#### 辅助队列
```java
/**
* 判断是否为完全二叉树
* @param root
* @return
*/
boolean isCompleteTree(TreeNode1 root) {
if(root == null) {
return true;
}
Queue<TreeNode1> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
TreeNode1 cur = queue.poll();
if(cur != null) {
queue.offer(cur.left);
queue.offer(cur.right);
} else {
break;
}
}
//依次判断队列中每一个元素是否为null;
while(!queue.isEmpty()) {
TreeNode1 top = queue.peek();
if(top != null){
return false;
}
queue.poll();
}
return true;
}
```
判断两棵二叉树是否相同
```java
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
// 判断一对节点是否相同
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
if (p.val != q.val) {
return false;
}
// 判断其他节点是否相同
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
```
判断一棵树是否是另一棵树的子树
```java
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null) {
return subRoot == null;
}
// 判断以 root 为根的二叉树是否和 subRoot 相同
if (isSameTree(root, subRoot)) {
return true;
}
// 去左右子树中判断是否有和 subRoot 相同的子树
return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode p, TreeNode q) {
// 判断一对节点是否相同
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
if (p.val != q.val) {
return false;
}
// 判断其他节点是否相同
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
```
判断是否平衡二叉树
平衡二叉树定义:一个二叉树*每个节点* 的左右两个子树的高度差的绝对值不超过 1
```java
class Solution {
public boolean isBalanced(TreeNode root) {
maxDepth(root);
return isBalanced;
}
// 记录二叉树是否平衡
boolean isBalanced = true;
// 输入一个节点,返回以该节点为根的二叉树的最大深度
int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
// if (!isBalanced) {
// // 随便返回一个值即可,旨在结束递归
// return -666;
// }
int leftMaxDepth = maxDepth(root.left);
int rightMaxDepth = maxDepth(root.right);
// 后序遍历位置
// 如果左右最大深度大于 1,就不是平衡二叉树
if (Math.abs(rightMaxDepth - leftMaxDepth) > 1) {
isBalanced = false;
}
return 1 + Math.max(leftMaxDepth, rightMaxDepth);
}
}
```
```java
class Solution {
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
return Math.abs(depth(root.left) - depth(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
private int depth(TreeNode root) {
if (root == null) return 0;
return Math.max(depth(root.left), depth(root.right)) + 1;
}
}
```
```java
class Solution {
public boolean isBalanced(TreeNode root) {
return recur(root) != -1;
}
private int recur(TreeNode root) {
if (root == null) return 0;
int left = recur(root.left);
if(left == -1) return -1;
int right = recur(root.right);
if(right == -1) return -1;
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
}
}
```
判断二叉树是否对称
```java
class Solution {
public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
if(leftTree == null || rightTree == null) {
return leftTree == rightTree;
}
if(leftTree.val != rightTree.val) {
return false;
}
return isSymmetricChild(leftTree.right,rightTree.left) &&
isSymmetricChild(leftTree.left,rightTree.right);
}
public boolean isSymmetric(TreeNode root) {
if(root == null) return true;
return isSymmetricChild(root.left,root.right);
}
}
```
根据先序遍历创建二叉树,并输出中序遍历结果
```java
/**
* 根据先序结果创建二叉树
*/
import java.util.*;
class TreeNode {
public char val;
public TreeNode left;
public TreeNode right;
public TreeNode(char val){
this.val = val;
}
}
public class Main{
public static int i = 0;
public static TreeNode createTree(String str) {
TreeNode root = null;
if(str.charAt(i) != '#') {
root = new TreeNode(str.charAt(i));
i++;
root.left = createTree(str);
root.right = createTree(str);
} else {
i++;
}
return root;
}
public static void inOrder(TreeNode root) {
if(root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextLine()) {
String str = in.nextLine();
TreeNode root = createTree(str);
inOrder(root);
}
}
}
```
二叉树的层序遍历
借助队列
```java
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while (!q.isEmpty()) {
int sz = q.size();
// 记录这一层的节点值
List<Integer> level = new LinkedList<>();
// for 循环控制每一层从左向右遍历
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
level.add(cur.val);
if (cur.left != null)
q.offer(cur.left);
if (cur.right != null)
q.offer(cur.right);
}
res.add(level);
}
return res;
}
}
```
递归
```java
class Solution {
List<List<Integer>> list = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
dns(root,0);
return list;
}
public void dns(TreeNode node,int lever){
if(node == null) return;
if(list.size()==lever) list.add(new ArrayList<Integer>());
list.get(lever).add(node.val);
dns(node.left,lever+1);
dns(node.right,lever+1);
}
}
```
根据前序遍历和中序遍历构造二叉树
![image-20220306134643805](D:/Typora/image-20220306134643805.png)
```java
class Solution {
/* 主函数 */
TreeNode buildTree(int[] preorder, int[] inorder) {
return build(preorder, 0, preorder.length - 1,
inorder, 0, inorder.length - 1);
}
/*
定义:前序遍历数组为 preorder[preStart..preEnd],
中序遍历数组为 inorder[inStart..inEnd],
构造这个二叉树并返回该二叉树的根节点
*/
TreeNode build(int[] preorder, int preStart, int preEnd,
int[] inorder, int inStart, int inEnd) {
if (preStart > preEnd) {
return null;
}
// root 节点对应的值就是前序遍历数组的第一个元素
int rootVal = preorder[preStart];
// rootVal 在中序遍历数组中的索引
int index = 0;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootVal) {
index = i;
break;
}
}
int leftSize = index - inStart;
// 先构造出当前根节点
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
root.left = build(preorder, preStart + 1, preStart + leftSize,
inorder, inStart, index - 1);
root.right = build(preorder, preStart + leftSize + 1, preEnd,
inorder, index + 1, inEnd);
return root;
}
}
```
根据中序遍历和后序遍历构造二叉树
![image-20220306135102395](D:/Typora/image-20220306135102395.png)
```java
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return build(inorder, 0, inorder.length - 1,
postorder, 0, postorder.length - 1);
}
/*
定义:
中序遍历数组为 inorder[inStart..inEnd],
后序遍历数组为 postorder[postStart..postEnd],
构造这个二叉树并返回该二叉树的根节点
*/
TreeNode build(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd) {
return null;
}
// root 节点对应的值就是后序遍历数组的最后一个元素
int rootVal = postorder[postEnd];
// rootVal 在中序遍历数组中的索引
int index = 0;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == rootVal) {
index = i;
break;
}
}
// 左子树的节点个数
int leftSize = index - inStart;
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
root.left = build(inorder, inStart, index - 1,
postorder, postStart, postStart + leftSize - 1);
root.right = build(inorder, index + 1, inEnd,
postorder, postStart + leftSize, postEnd - 1);
return root;
}
}
```
根据前序遍历和后序遍历构造二叉树
![image-20220306134532738](D:/Typora/image-20220306134532738.png)
```java
class Solution {
public TreeNode constructFromPrePost(int[] preorder, int[] postorder) {
return build(preorder, 0, preorder.length - 1,
postorder, 0, postorder.length - 1);
}
// 定义:根据 preorder[preStart..preEnd] 和 postorder[postStart..postEnd]
// 构建二叉树,并返回根节点。
TreeNode build(int[] preorder, int preStart, int preEnd,
int[] postorder, int postStart, int postEnd) {
if (preStart > preEnd) {
return null;
}
if (preStart == preEnd) {
return new TreeNode(preorder[preStart]);
}
// root 节点对应的值就是前序遍历数组的第一个元素
int rootVal = preorder[preStart];
// root.left 的值是前序遍历第二个元素
// 通过前序和后序遍历构造二叉树的关键在于通过左子树的根节点
// 确定 preorder 和 postorder 中左右子树的元素区间
int leftRootVal = preorder[preStart + 1];
// leftRootVal 在后序遍历数组中的索引
int index = 0;
for (int i = postStart; i < postEnd; i++) {
if (postorder[i] == leftRootVal) {
index = i;
break;
}
}
// 左子树的元素个数
int leftSize = index - postStart + 1;
// 先构造出当前根节点
TreeNode root = new TreeNode(rootVal);
// 递归构造左右子树
// 根据左子树的根节点索引和元素个数推导左右子树的索引边界
root.left = build(preorder, preStart + 1, preStart + leftSize,
postorder, postStart, index);
root.right = build(preorder, preStart + leftSize + 1, preEnd,
postorder, index + 1, postEnd - 1);
return root;
}
}
```
采用前序遍历把二叉树转为字符串
```java
class Solution {
// 定义:输入以 root 的二叉树,返回描述该二叉树的字符串
public String tree2str(TreeNode root) {
// base case
if (root == null) return "";
if (root.left == null && root.right == null) {
return root.val + "";
}
// 递归生成左右子树的字符串
String leftStr = tree2str(root.left);
String rightStr = tree2str(root.right);
// 后序遍历代码位置
// 根据左右子树字符串组装出前序遍历的顺序
// 按题目要求处理 root 只有一边有子树的情况
if (root.left != null && root.right == null) {
// 省略空的右子树
return root.val + "(" + leftStr + ")";
}
if (root.left == null && root.right != null) {
// 空的左子树不能省略
return root.val + "()" + "(" + rightStr + ")";
}
// 按题目要求处理 root 左右子树都不空的情况
return root.val + "(" + leftStr + ")" + "(" + rightStr + ")";
}
}
```
二叉搜索树
二叉搜索树转为双向循环链表
```java
class Solution {
Node head, pre;
public Node treeToDoublyList(Node root) {
if(root==null) return null;
dfs(root);
pre.right = head;
head.left =pre;//进行头节点和尾节点的相互指向,这两句的顺序也是可以颠倒的
return head;
}
public void dfs(Node cur){
if(cur==null) return;
dfs(cur.left);
//pre用于记录双向链表中位于cur左侧的节点,即上一次迭代中的cur,当pre==null时,cur左侧没有节点,即此时cur为双向链表中的头节点
if(pre==null) head = cur;
//反之,pre!=null时,cur左侧存在节点pre,需要进行pre.right=cur的操作。
else pre.right = cur;
cur.left = pre;//pre是否为null对这句没有影响,且这句放在上面两句if else之前也是可以的。
pre = cur;//pre指向当前的cur
dfs(cur.right);//全部迭代完成后,pre指向双向链表中的尾节点
}
}
```
二叉搜索树的搜索
```java
class Solution {
// 递归,利用二叉搜索树特点,优化
public TreeNode searchBST(TreeNode root, int val) {
if (root == null || root.val == val) {
return root;
}
if (val < root.val) {
return searchBST(root.left, val);
} else {
return searchBST(root.right, val);
}
}
}
class Solution {
// 迭代,利用二叉搜索树特点,优化,可以不需要栈
public TreeNode searchBST(TreeNode root, int val) {
while (root != null)
if (val < root.val) root = root.left;
else if (val > root.val) root = root.right;
else return root;
return null;
}
}
```
验证二叉搜索树
```java
//递归
public boolean isValidBST(TreeNode root) {
return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean validate(TreeNode node, long min, long max) {
if (node == null) {
return true;
}
if (node.val <= min || node.val >= max) {
return false;
}
return validate(node.left, min, node.val) && validate(node.right, node.val, max);
}
//迭代
class Solution {
public boolean isValidBST(TreeNode root) {
Deque<TreeNode> stack = new LinkedList<TreeNode>();
double inorder = -Double.MAX_VALUE;
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
// 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
if (root.val <= inorder) {
return false;
}
inorder = root.val;
root = root.right;
}
return true;
}
}
```
最近公共祖先
```java
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// base case
if (root == null) return null;
if (root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 情况 1
if (left != null && right != null) {
return root;
}
// 情况 2
if (left == null && right == null) {
return null;
}
// 情况 3
return left == null ? right : left;
}
}
```
二叉搜索树的最近公共祖先
```c++
//递归
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);
} else return root;
}
};
//迭代
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root) {
if (root->val > p->val && root->val > q->val) {
root = root->left;
} else if (root->val < p->val && root->val < q->val) {
root = root->right;
} else return root;
}
return NULL;
}
};
```