第六章二叉树part01
理论基础
需要了解 二叉树的种类,存储方式,遍历方式 以及二叉树的定义
文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html
递归遍历 (必须掌握)
二叉树的三种递归遍历掌握其规律后,其实很简单
题目链接/文章讲解/视频讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html
迭代遍历 (基础不好的录友,迭代法可以放过)
题目链接/文章讲解/视频讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E8%BF%AD%E4%BB%A3%E9%81%8D%E5%8E%86.html
统一迭代 (基础不好的录友,迭代法可以放过)
这是统一迭代法的写法, 如果学有余力,可以掌握一下
题目链接/文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E7%BB%9F%E4%B8%80%E8%BF%AD%E4%BB%A3%E6%B3%95.html
层序遍历
看完本篇可以一口气刷十道题,试一试, 层序遍历并不难,大家可以很快刷了十道题。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0102.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%B1%82%E5%BA%8F%E9%81%8D%E5%8E%86.html
树节点
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {
}
public TreeNode(int val) {
this.val = val;
}
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
递归
public class TreeRecursionTraversal {
public List<Integer> recursionTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
preOrderRecursion(root,res);
return res;
}
public void preOrderRecursion(TreeNode node, List<Integer> res){
if(node == null){
return;
}
res.add(node.val);
preOrderRecursion(node.left,res);
preOrderRecursion(node.right,res);
}
public void midOrderRecursion(TreeNode node, List<Integer> res){
if(node == null){
return;
}
preOrderRecursion(node.left,res);
res.add(node.val);
preOrderRecursion(node.right,res);
}
public void postOrderRecursion(TreeNode node, List<Integer> res){
if(node == null){
return;
}
preOrderRecursion(node.left,res);
preOrderRecursion(node.right,res);
res.add(node.val);
}
}
迭代
public class TreeIterationTraversal {
public List<Integer> preOrderIteration(TreeNode root){
List<Integer> res = new LinkedList<>();
LinkedList<TreeNode> stack=new LinkedList<>();
if(root!=null) stack.push(root);
while(!stack.isEmpty()){
TreeNode node=stack.pop();
res.add(node.val);
if(node.right!=null){
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
}
return res;
}
//后序遍历,先序遍历是中左右,后序遍历是左右中,那么我们只需要调整一下先序遍历的代码顺序,就变成中右左的遍历顺序,然后在反转result数组,输出的结果顺序就是左右中了
public List<Integer> postOrderIteration(TreeNode root){
List<Integer> res = new LinkedList<>();
LinkedList<TreeNode> stack=new LinkedList<>();
if(root!=null) stack.push(root);
while(!stack.isEmpty()){
TreeNode node=stack.pop();
res.add(node.val);
if(node.left!=null){
stack.push(node.left);
}
if(node.right!=null){
stack.push(node.right);
}
}
Collections.reverse(res);
return res;
}
/**
* 中序遍历为什么不一样?
* 迭代涉及俩个操作
* 1.处理:将元素放进result数组中
* 2.访问:遍历节点
*
* 因为前序遍历的顺序是中左右,先访问的元素是中间节点,要处理的元素也是中间节点,所以刚刚才能写出相对简洁的代码,因为要访问的元素和要处理的元素顺序是一致的,都是中间节点。
*
* 中序遍历是左中右,先访问的是二叉树顶部的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进result数组中),这就造成了处理顺序和访问顺序是不一致的。
*
*
* 在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。
**/
public List<Integer> midOrderIteration(TreeNode root){
List<Integer> res = new LinkedList<>();
LinkedList<TreeNode> stack=new LinkedList<>();
TreeNode cur = root;//记录遍历节点
while(cur!=null||!stack.isEmpty()){
if(cur!=null){// 指针来访问节点,访问到最底层
stack.push(cur);// 将访问的节点放进栈
cur=cur.left;
}else {
cur=stack.pop();// 从栈里弹出的数据,就是要处理的数据(放进result数组里的数据)
res.add(cur.val);
cur=cur.right;
}
}
return res;
}
}
统一迭代
public class UnifyIterationTraversal {
//统一迭代法 标记法 前序遍历
public List<Integer> unifyPreorderTraversal(TreeNode root) {
List<Integer> result = new LinkedList<>();
Stack<TreeNode> st = new Stack<>();
if (root != null) st.push(root);
while (!st.empty()) {
TreeNode node = st.peek();
if (node != null) {
st.pop(); // 将该节点弹出,避免重复操作,下面再将右左中节点添加到栈中
if (node.right!=null) st.push(node.right); // 添加右节点(空节点不入栈)
if (node.left!=null) st.push(node.left); // 添加左节点(空节点不入栈)
st.push(node); // 添加中节点
st.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。
} else { // 只有遇到空节点的时候,才将下一个节点放进结果集
st.pop(); // 将空节点弹出
node = st.peek(); // 重新取出栈中元素
st.pop();
result.add(node.val); // 加入到结果集
}
}
return result;
}
public List<Integer> unifyMidOrderTraversal(TreeNode root){
List<Integer> res=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
if(root!=null) stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.peek();
if(node!=null){
stack.pop();//预先弹出节点,避免重复操作,下面再将右中左节点添加到栈中
stack.push(node);
stack.push(null);// 中节点访问过,但是还没有处理,加入空节点做为标记。
if(node.right!=null){
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
}else {//遇到标记的空节点,收集结果
stack.pop();
TreeNode pop = stack.pop();
res.add(pop.val);
}
}
return res;
}
public List<Integer> unifyPostOrderTraversal(TreeNode root){
List<Integer> res=new ArrayList<>();
Stack<TreeNode> stack=new Stack<>();
if(root!=null) stack.push(root);
while (!stack.isEmpty()){
TreeNode node = stack.peek();
if(node!=null){
stack.pop();//预先弹出节点,避免重复操作,下面再将右右左节点添加到栈中
stack.push(node);
stack.push(null);// 中节点访问过,但是还没有处理,加入空节点做为标记。
if(node.right!=null){
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
}else {//遇到标记的空节点,收集结果
stack.pop();
node = stack.peek();
stack.pop();
res.add(node.val);
}
}
return res;
}
public static void main(String[] args) {
UnifyIterationTraversal unifyIterationTraversal = new UnifyIterationTraversal();
TreeNode node3 = new TreeNode(3); // Node at depth 2
TreeNode node2 = new TreeNode(2, node3, null); // Node at depth 1
TreeNode node1 = new TreeNode(1, null, node2);
unifyIterationTraversal.unifyPostOrderTraversal(node1);
}
}
层序遍历
public class TreeLevelOrderTraversal {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
res.add(level);
}
return res;
}
//递归法
public static List<List<Integer>> resList = new ArrayList<List<Integer>>();
public static List<List<Integer>> levelOrder2(TreeNode root) {
checkFun01(root,0);
//checkFun02(root);
return resList;
}
//BFS--递归方式
public static void checkFun01(TreeNode node, Integer deep) {
if (node == null) return;
deep++;
if (resList.size() < deep) {
//当层级增加时,list的Item也增加,利用list的索引值进行层级界定
List<Integer> item = new ArrayList<Integer>();
resList.add(item);
}
resList.get(deep - 1).add(node.val);
checkFun01(node.left, deep);
checkFun01(node.right, deep);
}
public static void main(String[] args) {
TreeNode root = new TreeNode(1);
root.left=new TreeNode(2);
root.right=new TreeNode(3);
root.left.left=new TreeNode(4);
root.left.right=new TreeNode(5);
root.right.left=new TreeNode(6);
root.right.right=new TreeNode(7);
levelOrder2(root);
}
}