树的两种遍历

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));
    }
}
相关推荐
Victor35610 分钟前
MongoDB(38)如何使用聚合进行投影?
后端
AI_56781 小时前
基于智优达平台的Python教学实践:从环境搭建到自动评测
开发语言·前端·人工智能·后端·python
IT_陈寒1 小时前
JavaScript开发者必备的5个高效调试技巧,90%的人都不知道最后一个!
前端·人工智能·后端
会编程的土豆1 小时前
Set 深度解析:去重、唯一性与你的智能抽屉
java·开发语言·后端·数据结构与算法
颜酱1 小时前
二分图核心原理与判定算法
javascript·后端·算法
奋斗小强1 小时前
前端工程化:从 Webpack 到 Vite,打包速度提升 10 倍的秘密
后端
我叫黑大帅2 小时前
Golang中实时推送的功臣 - WebSocket
后端·面试·go
朱雨鹏2 小时前
图解RocketMQ运行原理
后端·rocketmq
颜颜颜yan_2 小时前
从千毫秒到亚毫秒:连接条件下推如何让复杂 SQL 飞起来
后端
程序员小崔日记2 小时前
WebSocket 全面解析:让浏览器“实时说话”的黑科技(建议收藏)
后端·websocket·实时通信