day13 二叉树-基础+递归遍历+迭代遍历+统一迭代+层序遍历

## 6.Binary Tree
### 6.1 introduction
1.二叉树的定义:
```java
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;
    }
}
```

建了一个用于验证的二叉树组:
```java
class TreeBuilder {  
    public static TreeNode buildTree() {  
        // 根节点  
        TreeNode root = new TreeNode(1);  
  
        // 第二层  
        TreeNode level2Left = new TreeNode(2);  
        TreeNode level2Right = new TreeNode(3);  
        root.left = level2Left;  
        root.right = level2Right;  
  
        // 第三层  
        TreeNode level3Left1 = new TreeNode(4);  
        TreeNode level3Right1 = new TreeNode(5);  
        TreeNode level3Left2 = new TreeNode(6);  
        TreeNode level3Right2 = new TreeNode(7);  
  
        level2Left.left = level3Left1;  
        level2Left.right = level3Right1;  
        level2Right.left = level3Left2;  
        level2Right.right = level3Right2;  
  
        // 第四层  
        TreeNode level4Left1 = new TreeNode(8);  
        TreeNode level4Right1 = new TreeNode(9);  
        TreeNode level4Left2 = new TreeNode(10);  
        TreeNode level4Right2 = new TreeNode(11);  
        TreeNode level4Left3 = new TreeNode(12);  
        TreeNode level4Right3 = new TreeNode(13);  
        TreeNode level4Left4 = new TreeNode(14);  
        TreeNode level4Right4 = new TreeNode(15);  
  
        level3Left1.left = level4Left1;  
        level3Left1.right = level4Right1;  
  
        level3Right1.left = level4Left2;  
        level3Right1.right = level4Right2;  
  
        level3Left2.left = level4Left3;  
        level3Left2.right = level4Right3;  
  
        level3Right2.left = level4Left4;  
        level3Right2.right = level4Right4;  
  
        return root;  
    }  
}
```
2.种类
(1)满二叉树:深度k,节点数: $2^{k-1}$ 
![[满二叉树.png]]
(2)完全二叉树:深度h,底层节点数:1 ~ $2^{h-1}$
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。核心:底部一定从左到右连续。

(3)二叉搜索树
二叉搜索树是一个有序树。
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树

(4)平衡二叉搜索树
平衡二叉搜索树:又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
TreeMap, TreeSet均对应AVL。是有序的

3.二叉树的存储:
(1)链式存储:通过指针把分布在各个地址的节点串联一起。
![[链式存储二叉树.png]]

(2)顺序存储:元素在内存是连续分布
![[顺序存储二叉树.png]]
4.二叉树的遍历:
二叉树主要有两种遍历方式:
深度优先遍历:先往深走,遇到叶子节点再往回走。
    前序遍历(递归法,迭代法): 中左右
    中序遍历(递归法,迭代法): 左中右
    后序遍历(递归法,迭代法): 左右中
广度优先遍历:一层一层的去遍历。
    层次遍历(迭代法)

递归遍历 (Recursive Traversal): Recursive Traversal
    这包括前序遍历(Preorder Traversal)、中序遍历(Inorder Traversal)和后序遍历(Postorder Traversal)。
迭代遍历 (Iterative Traversal): Iterative Traversal
    迭代遍历通常指的是不使用递归函数,而是通过栈(Stack)或其他数据结构来实现二叉树的遍历。这种遍历方式对于前序遍历、中序遍历和后序遍历都是适用的。
统一迭代法 (Unified Iterative Method): Unified Iterative Approach
    这是一个比较宽泛的术语,通常指的是一种能够以一种通用的迭代方式来实现不同遍历顺序(前序、中序、后序)的方法。它可能会使用栈来模拟递归过程,但以一种更为统一或灵活的方式。需要注意的是,这个术语并不是特别标准,具体的实现方式可能因上下文而异。
层序遍历 (Level-order Traversal): Level-order Traversal 或 Breadth-First Traversal (BFT)
    层序遍历是使用队列(Queue)来按照从上到下、从左到右的顺序遍历二叉树的节点。这种遍历方式首先访问根节点,然后遍历左子树,接着遍历右子树,逐层进行。

### 6.2 Recursive Traversal 144 145 94
>[!tip] 递归遍历三步:
1.确认递归函数的参数和返回值:大多数二叉树算法的参数都只有节点和返回值
2.确定终止条件:遇到空节点的时候返回
3.确定单层递归的逻辑:

144 Preorder Traversal
94 Inorder Traversal
145 Postorder Traversal

```java
public class recursiveTraversal {  
    public List<Integer> preorderTraversal(TreeNode root) {  
        List<Integer> result = new ArrayList<>();  
        preorder(root,result);  
        return result;  
    }  
    void preorder(TreeNode root, List<Integer> res){  
        if(root == null) return;  
        res.add(root.val);  
        preorder(root.left,res);  
        preorder(root.right,res);  
    }  
//======================================================================  
    public List<Integer> inorderTraversal(TreeNode root) {  
        List<Integer> result = new ArrayList<>();  
        inorder(root,result);  
        return result;  
    }  
    void inorder(TreeNode root, List<Integer> res){  
        if(root == null) return;  
        inorder(root.left,res);  
        res.add(root.val);  
        inorder(root.right,res);  
    }  
//=============================================================================  
    public List<Integer> postorderTraversal(TreeNode root) {  
        List<Integer> result = new ArrayList<>();  
        postorder(root,result);  
        return result;  
    }  
    void postorder(TreeNode root, List<Integer> res){  
        if(root == null) return;  
        postorder(root.left,res);  
        postorder(root.right,res);  
        res.add(root.val);  
    }  
}  
class recursiveTraversalTest{  
    public static void main(String[] args) {  
        recursiveTraversal rt = new recursiveTraversal();  
        TreeBuilder tb = new TreeBuilder();  
        TreeNode root = tb.buildTree();  
        List<Integer> list = rt.preorderTraversal(root);  
        for(int i:list){  
            System.out.print(i+" ");  
        }  
    }  
}
```
### 6.3 Iterative Traversal
用栈模拟。
144 Preorder Traversal
这里需要注意的是,因为栈会优先弹出后放的元素,所以要先放入右,再放入左,即中右左的处理顺序。
```java
public List<Integer> preorderTraversal(TreeNode root) {  
    List<Integer> result = new ArrayList<>();  
    //剪枝  
    if(root == null) return result;  
  
    Stack<TreeNode> st = new Stack<>();  
    st.push(root);  
    while(!st.isEmpty()){  
        TreeNode node = st.pop();  
        //中  
        if(node != null){  
            result.add(node.val);  
        }else{  
            continue;  
        }  
        //右  
        if(node.right != null){  
            st.push(node.right);  
        }  
        //左  
        if(node.left != null){  
            st.push(node.left);  
        }  
    }  
    return result;  
}
```

145 Postorder Traversal
后序遍历入栈顺序:中-左-右 出栈顺序:中-右-左, 最后翻转结果
```java
public List<Integer> postorderTraversal(TreeNode root) {  
    List<Integer> result = new ArrayList<>();  
    if(root == null) return result;  
    Stack<TreeNode> stack = new Stack<>();  
    stack.push(root);  
    while(!stack.isEmpty()){  
        TreeNode node = stack.pop();  
        result.add(node.val);  
        if(node.left != null) stack.push(node.left);  
        if(node.right != null) stack.push(node.right);  
    }  
    Collections.reverse(result);  
    return result;  
}
```

94 Inorder Traversal
遍历顺序和处理顺序不一致。如果节点不为空,则存入栈,并继续向左;如果节点为空了,则将节点数字存入数组,节点数字更新为栈的出口第一个数字(弹出第一个数字),再将节点更新为右叶子。
 ```java
 public List<Integer> inorderTraversal(TreeNode root) {  
    List<Integer> result = new ArrayList<>();  
    if(root == null) return result;  
  
    Stack<TreeNode> stack  = new Stack<>();  
    TreeNode node = root;  
    while(node != null || !stack.isEmpty()){  
        if(node != null){  
            stack.push(node);  
            node = node.left;  
        }else{  
            node = stack.pop();  
            result.add(node.val);  
            node = node.right;  
        }  
    }  
    return result;  
}
```

### 6.4 Unified Iterative Method
要处理的节点放入栈之后,紧接着放入一个空指针作为标记。 
```java
public class unifiedIterativeTraversal {  
    public List<Integer> preorderTraversal(TreeNode root) {  
        List<Integer> result = new ArrayList<>();  
        if(root == null) return result;  
  
        Stack<TreeNode> stack = new Stack<>();  
        stack.push(root);  
  
        while(!stack.isEmpty()){  
            //当栈不为空的时候,才要取node节点。  
            TreeNode node = stack.peek();  
            if(node != null){  
                stack.pop();  
                //入栈顺序:右左中  
                if(node.right != null) stack.push(node.right);  
                if(node.left != null) stack.push(node.left);  
                stack.push(node);  
                stack.push(null); // 中节点访问过,但是还没有处理,加入空节点做为标记。  
            }else{  
                stack.pop();//弹出空节点  
                node = stack.peek();  
                result.add(node.val);  
                stack.pop();  
            }  
        }  
        return result;  
    }  
}  
class unifiedIterativeTraversalTest {  
    public static void main(String[] args) {  
        unifiedIterativeTraversal it = new unifiedIterativeTraversal();  
        TreeBuilder tb = new TreeBuilder();  
        TreeNode root = tb.buildTree();  
        List<Integer> list = it.preorderTraversal(root);  
        for(int i:list){  
            System.out.print(i+" ");  
        }  
    }  
}
```

### 6.5 Level-order Traversal
了解这个思路后有十道超绝逐层遍历题

102. Binary Tree Level Order Traversal
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
```java
public class levelOrderTraversal {  
    public List<List<Integer>> levelOrder(TreeNode root) {  
        List<List<Integer>> result = new LinkedList<>();//保存结果  
        if(root == null) return result;  
  
        Deque<TreeNode> deque = new LinkedList<>();  
        deque.offerLast(root);  
  
        while(!deque.isEmpty()){  
            int size = deque.size();  
            List<Integer> levelNums = new LinkedList<>();//保存每一层的结果  
            while(size > 0){  
                TreeNode node = deque.peekFirst();  
                levelNums.add(node.val);  
                deque.pollFirst();//要记得把添加过的元素弹出!  
                if(node.left != null) deque.offerLast(node.left);  
                if(node.right != null) deque.offerLast(node.right);  
                size--;  
            }  
            result.add(levelNums);  
        }  
        return result;  
    }  
}  
class levelOrderTraversalTest {  
    public static void main(String[] args) {  
        levelOrderTraversal lt = new levelOrderTraversal();  
        TreeBuilder tb = new TreeBuilder();  
        TreeNode root = tb.buildTree();  
        List<List<Integer>> list = lt.levelOrder(root);  
        for(List<Integer> levels :list){  
            System.out.print("[");  
            for(int nums : levels){  
                System.out.print(nums+" ");  
            }  
            System.out.println("]");  
        }  
    }  
}
```

107. Binary Tree Level Order Traversal II
Given the root of a binary tree, return the bottom-up level order traversal of its nodes' values. (i.e., from left to right, level by level from leaf to root).
```java
public List<List<Integer>> levelOrderBottom(TreeNode root) {  
    List<List<Integer>> result = new LinkedList<>();  
    if(root == null) return result;  
  
    Deque<TreeNode> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        List<Integer> nums = new LinkedList<>();  
        while(size>0){  
            TreeNode node = deque.peekFirst();  
            nums.add(node.val);  
            deque.pollFirst();  
            if(node.left != null) deque.offerLast(node.left);  
            if(node.right != null) deque.offerLast(node.right);  
            size--;  
        }  
        result.add(nums);  
    }  
    Collections.reverse(result);  
    return result;  
}
```
199. Binary Tree Right Side View
Given the root of a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.
```java
public List<Integer> rightSideView(TreeNode root) {  
    List<Integer> result = new LinkedList<>();  
    if(root == null) return result;  
  
    Deque<TreeNode> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        while (size > 0){  
            TreeNode node = deque.peekFirst();  
            if(size == 1){  
                result.add(node.val);  
            }  
            deque.pollFirst();  
            if(node.left != null) deque.offerLast(node.left);  
            if(node.right != null) deque.offerLast(node.right);  
            size--;  
        }  
    }  
    return result;  
}
public static void main(String[] args) {  
        levelOrderTraversal lt = new levelOrderTraversal();  
        TreeBuilder tb = new TreeBuilder();  
        TreeNode root = tb.buildTree();  
        List<Integer> list = lt.rightSideView(root);  
        for(int i : list){  
            System.out.print(i+" ");  
        }  
    }
```
637. Average of Levels in Binary Tree
Given the root of a binary tree, return the average value of the nodes on each level in the form of an array. Answers within 10-5 of the actual answer will be accepted.
```java
public List<Double> averageOfLevels(TreeNode root) {  
        List<Double> result = new LinkedList<>();  
        if(root == null) return result;  
  
        Deque<TreeNode> deque = new LinkedList<>();  
        deque.offerLast(root);  
  
        while(!deque.isEmpty()){  
//            double size = deque.size();  
//            double sum = 0;  
//            int count = (int) size;  
//            while(count > 0){  
//                TreeNode node = deque.peekFirst();  
//                sum += node.val;  
//                deque.pollFirst();  
//                if(node.left != null) deque.offerLast(node.left);  
//                if(node.right != null) deque.offerLast(node.right);  
//                count--;  
//            }  
//            result.add(sum/size);  
//这段while循环内的代码可以简化一下,deque的size就是要循环的次数。这样优化以后效率大大提高
            int levelSize = deque.size();  
            double sum = 0.0;  
            for (int i = 0; i < levelSize; i++) {  
                TreeNode node = deque.peekFirst();  
                deque.pollFirst();  
                sum += node.val;  
                if(node.left != null) deque.offerLast(node.left);  
                if(node.right != null) deque.offerLast(node.right);  
            }  
            result.add(sum/levelSize);  
        }  
        return result;  
    }
```
429. N-ary Tree Level Order Traversal
Given an n-ary tree, return the level order traversal of its nodes' values.
Nary-Tree input serialization is represented in their level order traversal, each group of children is separated by the null value (See examples).
```java
public List<List<Integer>> levelOrder(Node root) {  
    List<List<Integer>> result = new LinkedList<>();  
    if(root == null) return result;  
  
    Deque<Node> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        List<Integer> nums = new LinkedList<>();  
        while(size > 0){  
            Node node = deque.peekFirst();  
            nums.add(node.val);  
            deque.pollFirst();  
            List<Node> children = node.children;  
            for(Node cn : children){  
                deque.offerLast(cn);  
            }  
            size--;  
        }  
        result.add(nums);  
    }  
    return result;  
}
```
515. Find Largest Value in Each Tree Row
Given the root of a binary tree, return an array of the largest value in each row of the tree (0-indexed).
```java
//515.在每个树行中找最大值(opens new window)  
public List<Integer> largestValues(TreeNode root) {  
    List<Integer> result = new LinkedList<>();  
    if(root == null) return result;  
  
    Deque<TreeNode> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        int max = deque.peek().val;  
        while(size > 0){  
            TreeNode node = deque.peekFirst();  
            deque.pollFirst();  
            max = Math.max(max,node.val);  
            if(node.left != null) deque.offerLast(node.left);  
            if(node.right != null) deque.offerLast(node.right);  
            size--;  
        }  
        result.add(max);  
    }  
    return result;  
}
```
116. Populating Next Right Pointers in Each Node
You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
```java
//116.填充每个节点的下一个右侧节点指针(opens new window)  
public Node116 connect(Node116 root) {  
    if(root == null) return root;  
    Deque<Node116> deque = new LinkedList<>();  
    deque.add(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        Node116 cur = deque.pollFirst();  
        if (cur.left != null) deque.add(cur.left);  
        if (cur.right != null) deque.add(cur.right);  
  
        for (int i = 1; i < size; i++) {  
            Node116 next = deque.pollFirst();  
            if (next.left != null) deque.add(next.left);  
            if (next.right != null) deque.add(next.right);  
  
            cur.next = next;  
            cur = next;  
        }  
    }  
    return root;  
}
```
117. Populating Next Right Pointers in Each Node II
Given a binary tree
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.
Initially, all next pointers are set to NULL.
```java
public Node116 connect117(Node116 root) {  
    if(root == null) return root;  
    Deque<Node116> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        Node116 cur = deque.pollFirst();  
        if(cur.left != null) deque.offerLast(cur.left);  
        if(cur.right != null) deque.offerLast(cur.right);  
  
        for (int i = 1; i < size; i++) {  
            Node116 next = deque.pollFirst();  
            if(next.left != null) deque.offerLast(next.left);  
            if(next.right != null) deque.offerLast(next.right);  
  
            cur.next = next;  
            cur = next;  
        }  
    }  
    return root;  
}
```
104. Maximum Depth of Binary Tree
Given the root of a binary tree, return its maximum depth.
A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
```java
public int maxDepth(TreeNode root) {  
    int depth = 0;  
    if(root == null) return depth;  
  
    Deque<TreeNode> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
            while(size > 0){  
                TreeNode node = deque.pollFirst();//放在里面定义,确保每次size--都可以弹出一个node。  
                if(node.left != null) deque.offerLast(node.left);  
                if(node.right != null) deque.offerLast(node.right);  
                size--;  
            }  
        depth++;  
    }  
    return depth;  
}
```
111. Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth.
The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.
Note: A leaf is a node with no children.
```java
public int minDepth(TreeNode root) {  
    int depth = 0;  
    if(root == null) return depth;  
  
    Deque<TreeNode> deque = new LinkedList<>();  
    deque.offerLast(root);  
  
    while(!deque.isEmpty()){  
        int size = deque.size();  
        depth++;  
        for (int i = 0; i < size; i++) {  
            TreeNode node = deque.pollFirst();  
            if(node.left == null && node.right == null){  
                return depth;  
            }  
            if(node.left != null) deque.offerLast(node.left);  
            if(node.right != null) deque.offerLast(node.right);  
        }  
    }  
    return depth;  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值