树的两种遍历

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));
    }
}
相关推荐
GetcharZp15 小时前
GitHub 49K+ Star!C++ 开发者必知的 JSON 神级库:从零到精通全指北
后端
xujinwei_gingko15 小时前
SpringBoot整合WebSocket
spring boot·后端·websocket
智码看视界15 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
程序员cxuan15 小时前
Claude Fable 5 来了
人工智能·后端·程序员
JS菌16 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
wang090716 小时前
自己动手写一个spring之IOC_2
java·后端·spring
ltl17 小时前
推理退化:为什么大模型会输出乱码、死循环和无意义文本
后端
ltl17 小时前
架构视图与文档:C4 模型从入门到实战
后端
IT_陈寒20 小时前
Redis持久化这个坑,我爬了一整天才出来
前端·人工智能·后端
无风听海20 小时前
多租户系统中的 OIDC:Discovery 端点与联合登录的深度实践
后端·python·flask