树的两种遍历

1 树的序遍历

前序遍历、中序遍历、后序遍历

1.1 遍历方式

都有点抽象,需要结合代码和画图来看

  1. 递归遍历
  2. 非递归遍历:都是用栈来解决
    1. 前序遍历
      • 用一个栈,先进右再进左
    2. 中序遍历
      • 用一个栈,先进左,左出,再进右
    3. 后序遍历
      • 用两个栈,一个栈和前序遍历反着来,出的元素进另一个栈,进完之后全打印
      • 用一个栈,先解决左边的,再解决右边的。

1.2 代码实现

java 复制代码
public class RecursiveTraversalBT {
    public static class Node {
        public int val;
        public Node left;
        public Node right;
        public Node(int val){
            this.val = val;
        }
    }

    // 递归遍历
    public static void pre1(Node head) {
        if (head == null) {
            return;
        }
        System.out.print(head.val + " ");
        pre1(head.left);
        pre1(head.right);
    }

    public static void in1(Node head) {
        if (head == null) {
            return;
        }
        in1(head.left);
        System.out.print(head.val + " ");
        in1(head.right);
    }

    public static void pos1(Node head) {
        if (head == null) {
            return;
        }
        pos1(head.left);
        pos1(head.right);
        System.out.print(head.val + " ");
    }

    // 非递归遍历(栈)
    public static void pre2(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.push(head);
            while (!stack.isEmpty()) {
                head = stack.pop();
                System.out.print(head.val + " ");
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
    }

    public static void in2(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || head != null) {
                if (head != null) {
                    stack.push(head);
                    head = head.left;
                }else {
                    head = stack.pop();
                    System.out.print(head.val + " ");
                    head = head.right;
                }
            }
        }
    }

    public static void pos2(Node head) {
        if (head != null) {
            Stack<Node> stack1 = new Stack<>();
            Stack<Node> stack2 = new Stack<>();
            stack1.push(head);
            while (!stack1.isEmpty()){
                head = stack1.pop();
                stack2.push(head);
                if (head .left != null) {
                    stack1.push(head.left);
                }
                if (head .right != null) {
                    stack1.push(head.right);
                }
            }
            while (!stack2.isEmpty()) {
                System.out.print(stack2.pop().val + " ");
            }
        }
    }

    // 后序遍历的第三种写法(只用一个栈)
    public static void pos3(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.push(head);
            Node help = null;
            while (!stack.isEmpty()) {
                help = stack.peek();
                if (help.left !=null && head != help.left && head != help.right){
                    stack.push(help.left);
                } else if (help.right != null && head != help.right) {
                    stack.push(help.right);
                }else {
                    System.out.print(stack.pop().val + " ");
                    head = help;
                }
            }
        }

    }
    
    public static void main(String[] args) {
        Node head = new Node(1);
        head.left = new Node(2);
        head.right = new Node(3);
        head.left.left = new Node(4);
        head.left.right = new Node(5);
        head.right.left = new Node(6);
        head.right.right = new Node(7);

        pos2(head);
        System.out.println();
        pos3(head);
        System.out.println();

    }
}

2 树的层遍历

2.1 遍历方式

树的最宽层有几个节点?

  1. 借助Map来查找
    1. 定义一个队列和一个HashMap,都把头节点放进去,其中Map中存放的是当前节点和其对应的层数
    2. 每次弹出一个节点,就把这个节点的左右子节点都放进队列和对应的Map
    3. 如果还没到下一层,那么当前层的节点数就要加一
    4. 如果到了下一层,就把上一层的节点数和之前层的节点数比较
    5. 返回节点数最多的层的节点数
  2. 只用队列
    1. 定义一个当前层的最左节点,一个下一层的最左节点
    2. 当弹出的节点等于当前层最左节点时,记录当前层节点数并与之前层的最大节点数比较,哪个大留哪个
    3. 这个时候就要进入下一次,所以当前层节点数置为0,当前层最左节点置为下一层最左节点

4.2.2 代码实现

java 复制代码
public class TreeMaxWidth {
    public static class Node {
        public int val;
        public Node left;
        public Node right;
        public Node(int val) {
            this.val = val;
            left = null;
            right = null;
        }
    }

    public static int maxWidthUseMap(Node head) {
        if (head == null) {
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        HashMap<Node, Integer> hashMap = new HashMap<>();
        hashMap.put(head, 1);
        int curLevelNodes = 0;
        int curLevel = 1;
        int max = 0;
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            int curNodeLevel = hashMap.get(cur);
            if (cur.left != null) {
                queue.add(cur.left);
                hashMap.put(cur.left, curNodeLevel + 1);
            }
            if (cur.right != null) {
                queue.add(cur.right);
                hashMap.put(cur.right, curNodeLevel + 1);
            }
            if (curLevel == curNodeLevel) {
                curLevelNodes++;
            }else {
                max = Math.max(max, curLevelNodes);
                curLevel++;
                curLevelNodes = 1;
            }
        }
        max = Math.max(max, curLevelNodes);
        return max;
    }

    public static int maxWidthNoMap (Node head) {
        if (head == null) {
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        Node curEnd = head;
        Node nextEnd = null;
        int max = 0;
        int curLevelNodes = 0;
        while (!queue.isEmpty()) {
            Node cur = queue.poll();
            if (cur.left != null) {
                queue.add(cur.left);
                nextEnd = cur.left;
            }
            if (cur.right != null) {
                queue.add(cur.right);
                nextEnd = cur.right;
            }
            curLevelNodes++;
            if (cur == curEnd) {
                max = Math.max(max, curLevelNodes);
                curLevelNodes = 0;
                curEnd = nextEnd;
            }
        }
        return max;
    }

    public static void main(String[] args) {
        Node head = new Node(1);
        head.left = new Node(2);
        head.right = new Node(3);
        head.left.left = new Node(4);
        head.left.right = new Node(5);
        head.right.left = new Node(6);
        head.right.right = new Node(7);
        head.left.right.left = new Node(8);
        head.right.left.right = new Node(9);
        
        System.out.println(maxWidthNoMap(head));
    }
}
相关推荐
爱吃牛肉的大老虎10 小时前
网络传输架构之GraphQL讲解
后端·架构·graphql
稚辉君.MCA_P8_Java12 小时前
Gemini永久会员 containerd部署java项目 kubernetes集群
后端·spring cloud·云原生·容器·kubernetes
yihuiComeOn13 小时前
[源码系列:手写Spring] AOP第二节:JDK动态代理 - 当AOP遇见动态代理的浪漫邂逅
java·后端·spring
e***716714 小时前
Spring Boot项目接收前端参数的11种方式
前端·spring boot·后端
程序猿小蒜14 小时前
基于springboot的的学生干部管理系统开发与设计
java·前端·spring boot·后端·spring
q***563814 小时前
Spring容器初始化扩展点:ApplicationContextInitializer
java·后端·spring
菜鸟‍15 小时前
【后端学习】MySQL数据库
数据库·后端·学习·mysql
Codebee15 小时前
30 分钟落地全栈交互:OneCode CLI+SVG 排课表实战
后端
TechTrek16 小时前
Spring Boot 4.0正式发布了
java·spring boot·后端·spring boot 4.0
飞梦工作室16 小时前
企业级 Spring Boot 邮件系统开发指南:从基础到高可用架构设计
java·spring boot·后端