二叉树理论基础
1.二叉树的种类:满二叉树:深度为k,有2^k-1个节点的二叉树;完全二叉树:除最后一层外的所有层全满,而且最后一层的结点集中在最左边,中间不能空
2.二叉搜索树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树
3.平衡二叉搜索树:在二叉搜索树的基础上。左右子树的高度差绝对值不超过1。(题外话:HashMap/HashSet: 哈希表实现,平均时间复杂度 O(1);TreeMap/TreeSet: 红黑树实现,时间复杂度 O(log n);LinkedHashMap/LinkedHashSet: 哈希表 + 双向链表,保持插入顺序;ConcurrentHashMap: 分段锁/红黑树 + 哈希表,适用于并发场景。)
4.二叉树的存储方式:二叉树可以链式存储,也可以顺序存储(数组:i,左2i+1,右2i+2)。
5.二叉树的遍历方式:深度优先遍历:前序遍历(中左右)、中序遍历(左中右)、后序遍历(左右中);广度优先遍历:层次遍历(迭代法)
6.二叉树的定义:
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.二叉树的前序遍历
文档讲解︰代码随想录(programmercarl.com)
日期:2024-09-09
想法:1.递归:递归三要素:确定递归函数的参数和返回值,确定终止条件,确定单层递归的逻辑;2.迭代:递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,所以用栈来做迭代法,入栈根结点,每次取“中“位置的,再入栈右左(出栈是才能是左右)。
Java代码如下:
//递归
class Solution {public void preOrder(TreeNode root, List<Integer> list){if(root == null){return;}list.add(root.val);preOrder(root.left, list);preOrder(root.right, list);}public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<Integer>();preOrder(root, list);return list;}
}
//迭代
class Solution {public List<Integer> preorderTraversal(TreeNode root) {Deque<TreeNode> st = new LinkedList<>();List<Integer> list = new ArrayList<>();if(root == null){return list;}st.push(root);while(!st.isEmpty()){TreeNode node = st.pop();list.add(node.val);if(node.right != null){st.push(node.right);}if(node.left != null){st.push(node.left);}}return list;}
}
总结:前序中左右,递归确定三要素,递归函数的参数和返回,递归中止条件,单层逻辑;迭代用栈来完成,想象怎么进,出的时候才能顺序正确。
二叉树的后序遍历
题目链接:145.二叉树的后序遍历
文档讲解︰代码随想录(programmercarl.com)
日期:2024-09-09
Java代码如下:
//递归
class Solution {public void postOrder(TreeNode root, List<Integer> list){if(root == null){return;}postOrder(root.left, list);postOrder(root.right, list);list.add(root.val);}public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<Integer>();postOrder(root, list);return list;}
}
//迭代
class Solution {public List<Integer> postorderTraversal(TreeNode root) {Deque<TreeNode> st = new ArrayDeque<>();List<Integer> list = new ArrayList<>();if(root == null){return list;}st.push(root);while(!st.isEmpty()){TreeNode node = st.pop();list.add(node.val);if(node.left != null){st.push(node.left);}if(node.right != null){st.push(node.right);}}Collections.reverse(list);return list;}
}
总结:后序左右中(中右左反着),跟前序很类似。
二叉树的中序遍历
题目链接:94.二叉树的中序遍历
文档讲解︰代码随想录(programmercarl.com)
日期:2024-09-09
想法:中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点,需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素
Java代码如下:
//递归
class Solution {public void inOrder(TreeNode root, List<Integer> list){if(root == null){return;}inOrder(root.left, list);list.add(root.val);inOrder(root.right, list);}public List<Integer> inorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<Integer>();inOrder(root, list);return list;}
}
//迭代
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> result = new ArrayList<>();if (root == null){return result;}Deque<TreeNode> st = new ArrayDeque<>();TreeNode cur = root;while (cur != null || !st.isEmpty()){if (cur != null){st.push(cur);cur = cur.left;}else{cur = st.pop();result.add(cur.val);cur = cur.right;}}return result;}
}
总结:中序,左中右,迭代法与前后序不一样,得先左边走到底,再中,再右。
二叉树的层序遍历
题目链接:102.二叉树的层序遍历
107.二叉树的层次遍历II
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的层序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
104.二叉树的最大深度
111.二叉树的最小深度
文档讲解︰代码随想录(programmercarl.com)
日期:2024-09-09
想法:
Java代码如下:
总结: