数据结构-二叉树

一、二叉树的相关概念
1、满二叉树

满二叉树:每一层都是满节点的状态。
深度为k的满二叉树一共有2^k-1个节点。
每层有2^(k-1)个节点。

2、完全二叉树

完全二叉树:除了最底层的节点没有填满外,其他的层的节点数都是达到了最大值。

3、二叉搜素树

二叉搜素树:某节点的左子树都是小于该节点值的,右子树都是大于该节点值的。
中序遍历之后是一个顺序数组。

4、平衡二叉搜索树

1⃣️是二叉搜索树
2⃣️左右子树的高度差的绝对值不超过1。

二、二叉树遍历方式
1、二叉树前序遍历
1.1 递归遍历
// 前序遍历
List<Integer> resList;
public List<Integer> preorderTraversal(TreeNode root) {
    resList = new ArrayList<>();
    preOrder(root);
    return resList;
}
public void preOrder(TreeNode node) {
    if (node == null) return;
    resList.add(node.val);
    preOrder(node.left);
    preOrder(node.right);
}
1.2 迭代遍历

因为递归就是将一个一个函数押入栈中,所以可以通过栈来达到遍历的目的。
前序遍历的顺序是中左右,我们先把根节点压入栈中,然后弹出栈,将其右子节点和左子节点先后压入栈中,之所以是先压入右子节点再压入左子节点,是因为这样弹出的顺序就是左右了。

public List<Integer> preorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) return res;
    Stack<TreeNode> stack = new Stack<>();
    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;
}
2、二叉树中序遍历
2.1 递归遍历
// 中序遍历
List<Integer> resList;
public List<Integer> inorderTraversal(TreeNode root) {
    resList = new ArrayList<>();
    inOrder(root);
    return resList;
}
public void inOrder(TreeNode node) {
    if (node == null) return;
    inOrder(node.left);
    resList.add(node.val);
    inOrder(node.right);
}
2.2 迭代遍历
public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) return res;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
        if (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }else {
            cur = stack.pop();
            res.add(cur.val);
            cur = cur.right;
        }
    }
    return res;
}
3、二叉树后序遍历
3.1 递归遍历
// 后续遍历
List<Integer> resList;
public List<Integer> postorderTraversal(TreeNode root) {
    resList = new ArrayList<>();
    postOrder(root);
    return resList;
}
public void postOrder(TreeNode node) {
    if (node == null) return;
    postOrder(node.left);
    postOrder(node.right);
    resList.add(node.val);
}
3.2 迭代遍历
public List<Integer> postorderTraversal(TreeNode root) {
    List<Integer> res = new ArrayList<>();
    if (root == null) return res;
    Stack<TreeNode> stack = new Stack<>();
    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;
}
4、二叉树层序遍历
4.1 递归遍历
List<List<Integer>> resList;
    public List<List<Integer>> levelOrder(TreeNode root) {
        resList = new ArrayList<>();
        levelOrderUnit(root, 0);
        return resList;
    }
    public void levelOrderUnit(TreeNode root, int deep) {
        if (root == null) return;
        deep++;
        if (resList.size() < deep) {
            List<Integer> list = new ArrayList<>();
            resList.add(list);
        }
        resList.get(deep-1).add(root.val);
        levelOrderUnit(root.left, deep);
        levelOrderUnit(root.right, deep);
    }
4.2 迭代遍历
public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> resList = new ArrayList<>();
    Queue<TreeNode> queue = new LinkedList<>();
    if (root == null) return resList;
    queue.offer(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        List<Integer> list = new ArrayList<>();
        while (size > 0) {
            TreeNode node = queue.poll();
            list.add(node.val);
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
            size--;
        }
        resList.add(list);
    }
    return resList;
}
三、二叉树的属性
1、对称二叉树
// 递归
public boolean isSymmetric(TreeNode root) {
    return isSymmetricTree(root.left, root.right);
}
public boolean isSymmetricTree(TreeNode left, TreeNode right) {
    if (left == null && right == null) return true;
    if (left == null || right == null || left.val != right.val) return false;
    return isSymmetricTree(left.left, right.right) && isSymmetricTree(left.right, right.left);
}
// 迭代
public boolean isSymmetric(TreeNode root) {
    Deque<TreeNode> deque = new LinkedList<>();
    deque.offerFirst(root.left);
    deque.offerLast(root.right);
    while (!deque.isEmpty()) {
        TreeNode left = deque.pollFirst();
        TreeNode right = deque.pollLast();
        if (left == null && right == null ) continue;
        if (left == null || right == null || left.val != right.val) return false;
        deque.offerFirst(left.left);
        deque.offerFirst(left.right);
        deque.offerLast(right.right);
        deque.offerLast(right.left);
    }
    return true;
}
2、二叉树的最大深度
// 递归
public int maxDepth(TreeNode root) {
    if (root == null) return 0;
    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
// 迭代
public int maxDepth(TreeNode root) {
    int deep = 0;
    if (root == null) return deep;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        deep++;
        while (size > 0) {
            TreeNode node = queue.poll();
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
            size--;
        }
    }
    return deep;
}
3、二叉树的最小深度
// 递归
public int minDepth(TreeNode root) {
    if (root == null) return 0;
    int leftDepth = minDepth(root.left);
    int rightDepth = minDepth(root.right);
    if (root.left == null) return rightDepth + 1;
    if (root.right == null) return leftDepth + 1;
    return Math.min(leftDepth, rightDepth) + 1;
}
// 迭代
public int minDepth(TreeNode root) {
    if (root == null) return 0;
    Queue<TreeNode> queue = new LinkedList<>();
    int depth = 0;
    queue.offer(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        depth++;
        while (size > 0) {
            TreeNode node = queue.poll();
            if (node.left == null && node.right == null) return depth;
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
            size--;
        }
    }
    return depth;
}
4、完全二叉树的节点个数
// 递归
public int countNodes(TreeNode root) {
    if (root == null) return 0;
    return countNodes(root.left) + countNodes(root.right) + 1;
}
// 迭代
public int countNodes(TreeNode root) {
    if (root == null) return 0;
    Queue<TreeNode> queue = new ArrayDeque<>();
    int res = 0;
    queue.offer(root);
    while (!queue.isEmpty()) {
        int size = queue.size();
        while (size > 0) {
            TreeNode node = queue.poll();
            res++;
            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
            size--;
        }
    }
    return res;
}
// 完全二叉树解法
public int countNodes(TreeNode root) {
    if (root == null) return 0;

    int leftDepth = getDepth(root.left);
    int rightDepth = getDepth(root.right);
    if (leftDepth == rightDepth) {// 左子树是满二叉树
        // 2^leftDepth其实是 (2^leftDepth - 1) + 1 ,左子树 + 根结点
        return (1 << leftDepth) + countNodes(root.right);
    } else {// 右子树是满二叉树
        return (1 << rightDepth) + countNodes(root.left);
    }
}
public int getDepth(TreeNode node) {
    int depth = 0;
    while (node != null) {
        node = node.left;
        depth++;
    }
    return depth;
}
5、平衡二叉树
public boolean isBalanced(TreeNode root) {
    return height(root) >= 0;
}
public int height(TreeNode root){
    if (root == null) return 0;
    int left = height(root.left);
    int right = height(root.right);
    if (left == -1 || right == -1 || Math.abs(left-right) > 1) return -1;
    else return Math.max(left,right) + 1;
}
6、二叉树的所有路径
// 递归
List<String> resList;
public List<String> binaryTreePaths(TreeNode root) {
    resList = new ArrayList<>();
    if (root == null) return resList;
    getPath(root, new ArrayList<>());
    return resList;
}
public void getPath(TreeNode node, List<Integer> path) {
    path.add(node.val);
    if (node.left == null && node.right == null) {
        resList.add(getPathString(path));
        return;
    }
    if (node.left != null) {
        getPath(node.left, path);
        path.remove(path.size() - 1);
    }
    if (node.right != null) {
        getPath(node.right, path);
        path.remove(path.size() - 1);
    }
}
private String getPathString(List<Integer> path) {
    StringBuilder builder = new StringBuilder();
    builder.append(path.get(0));
    for (int i = 1; i < path.size(); i++) {
        builder.append("->").append(path.get(i));
    }
    return builder.toString();
}
7、左叶子之和
// 递归
public int sumOfLeftLeaves(TreeNode root) {
    if (root == null) return 0;
    if (root.left != null && root.left.left == null && root.left.right == null) return root.left.val + sumOfLeftLeaves(root.right);
    else return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
8、找左下角的值
public int findBottomLeftValue(TreeNode root) {
    Queue<TreeNode> queue = new ArrayDeque<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        root = queue.poll();
        // 先右后左,最后一个就是最左边的叶子节点
        if (root.right != null) queue.offer(root.right);
        if (root.left != null) queue.offer(root.left);
    }
    return root.val;
}
9、路经总和
public boolean hasPathSum(TreeNode root, int targetSum) {
    if (root == null) return false;
    if (root.left == null && root.right == null) return targetSum == root.val;
    targetSum -= root.val;
    return hasPathSum(root.left, targetSum) || hasPathSum(root.right, targetSum);
}
四、二叉树的构造与修改
1、反转二叉树
// 递归
public TreeNode invertTree(TreeNode root) {
    if (root == null) return null;
    TreeNode tmp = root.left;
    root.left = invertTree(root.right);
    root.right = invertTree(tmp);
    return root;
}
2、中序后续遍历序列构造二叉树
// 注意这个方法!
int[] inorder;
int[] postorder;
int index_post;
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
    this.inorder = inorder;
    this.postorder = postorder;
    index_post = postorder.length-1;
    for (int i = 0; i < inorder.length; i++) {
        map.put(inorder[i], i);
    }
    return helper(0, inorder.length-1);
}
private TreeNode helper(int left, int right) {
    if (left > right) return null;
    TreeNode node = new TreeNode(postorder[index_post]);
    int index = map.get(postorder[index_post--]);
    node.right = helper(index + 1, right);
    node.left = helper(left, index - 1);
    return node;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
    return buildTreeUnit(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public TreeNode buildTreeUnit(int[] inorder, int i, int j, int[] postorder, int x, int y) {
    if (i > j || x > y) return null;
    int k = i;
    for (; k <= j; k++) {
        if (inorder[k] == postorder[y]) break;
    }
    TreeNode root = new TreeNode(postorder[y]);
    root.left = buildTreeUnit(inorder, i, k-1, postorder, x, x+k-i-1);
    root.right = buildTreeUnit(inorder, k+1, j, postorder, x+k-i, y-1);
    return root;
}
3、最大二叉树
public TreeNode constructMaximumBinaryTree(int[] nums) {
    return constructBinaryTree(nums, 0, nums.length-1);
}
public TreeNode constructBinaryTree(int[] nums, int l, int r) {
    if (l > r) return null;
    if (l == r) return new TreeNode(nums[l]);
    // 寻找范围内最大值
    int index = l;
    int max = nums[l];
    for (int i = l+1; i <= r; i++) {
        if (nums[i] > max) {
            index = i;
            max = nums[i];
        }
    }
    TreeNode root = new TreeNode(max);
    root.left = constructBinaryTree(nums, l, index - 1);
    root.right = constructBinaryTree(nums, index + 1, r);
    return root;
}
4、合并二叉树
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
    if (root1 == null && root2 == null) return null;
    if (root1 == null) return root2;
    if (root2 == null) return root1;
    TreeNode node = new TreeNode();
    node.val = root1.val + root2.val;
    node.left = mergeTrees(root1.left, root2.left);
    node.right = mergeTrees(root1.right, root2.right);
    return node;
}
5、最近公公祖先
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root == null || root == p || root == q) { // 递归结束条件
        return root;
    }

    // 后序遍历
    TreeNode left = lowestCommonAncestor(root.left, p, q);
    TreeNode right = lowestCommonAncestor(root.right, p, q);

    if(left == null && right == null) { // 若未找到节点 p 或 q
        return null;
    }else if(left == null && right != null) { // 若找到一个节点
        return right;
    }else if(left != null && right == null) { // 若找到一个节点
        return left;
    }else { // 若找到两个节点
        return root;
    }
}
五、二叉搜索树的属性
1、二叉搜索树中的搜索
public TreeNode searchBST(TreeNode root, int val) {
    if (root == null) return null;
    if (root.val == val) return root;
    return root.val > val ? searchBST(root.left, val) : searchBST(root.right, val);
}
2、验证二叉搜索树

注意这道题,不能简单粗暴的判断左右两个节点跟该节点的比较。

// 递归
TreeNode max;
public boolean isValidBST(TreeNode root) {
    if (root == null) return true;
    // 左
    boolean left = isValidBST(root.left);
    if (!left) return false;
    // 中
    if (max != null && max.val >= root.val) return false;
    max = root;
    // 右
    boolean right = isValidBST(root.right);
    return right;
}
// 迭代
public boolean isValidBST(TreeNode root) {
    if (root == null) return true;
    Stack<TreeNode> stack = new Stack<>();
    TreeNode prev = null;
    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }
        TreeNode node = stack.pop();
        if (prev != null && prev.val >= node.val) return false;
        prev = node;
        root = node.right;
    }
    return true;
}
3、二叉搜索树的最小绝对差
// 递归1
int min = Integer.MAX_VALUE;
TreeNode prev;
public int getMinimumDifference(TreeNode root) {
    getMinimum(root);
    return min;
}
public void getMinimum(TreeNode root) {
    if (root == null) return;
    getMinimum(root.left);
    if (prev != null) min = Math.min(min, root.val - prev.val);
    prev = root;
    getMinimum(root.right);
}


// 递归2
int min = Integer.MAX_VALUE;
TreeNode prev;
public int getMinimumDifference(TreeNode root) {
    if (root == null) return min;
    min = getMinimumDifference(root.left);
    if (prev != null) min = Math.min(min, root.val - prev.val);
    prev = root;
    return getMinimumDifference(root.right);
}
// 迭代
int min = Integer.MAX_VALUE;
public int getMinimumDifference(TreeNode root) {
    Stack<TreeNode> stack = new Stack<>();
    TreeNode prev = null;
    while (root != null || !stack.isEmpty()) {
        while (root != null) {
            stack.push(root);
            root = root.left;
        }

        TreeNode pop = stack.pop();
        if (prev != null) min = Math.min(min, pop.val - prev.val);
        prev = pop;
        root = pop.right;
    }
    return min;
}
4、二叉搜索树中的众数

注意这道题,用到很多小点

List<Integer> resList;
TreeNode prev;
int maxCount;
int count;
public int[] findMode(TreeNode root) {
    resList = new ArrayList<>();
    prev = null;
    maxCount = 0;
    count = 0;
    findModeUnit(root);
    return resList.stream().mapToInt(Integer::intValue).toArray();
}
public void findModeUnit(TreeNode root) {
    if (root == null) return;
    findModeUnit(root.left);

    // 中
    if (prev == null || prev.val != root.val) {
        count = 1;
    } else if (prev.val == root.val) {
        count++;
    }
    // 如果root的值和前一个指针的值不相等
    // 当前的count是前一个指针的值的个数,与maxCount进行比较
    // 1、如果小于maxCount,就直接跳过,将count设置为1即可
    // 2、如果等于maxCount,就直接讲prev的值假如到resList中
    // 3、如果大于maxCount,就将resList清空,更新maxCount的值,将prev的值加入resList中
    if (count == maxCount) {
        resList.add(root.val);
    } else if (count > maxCount) {
        maxCount = count;
        resList.clear();
        resList.add(root.val);
    }
    prev = root;
    findModeUnit(root.right);
}
5、二叉树转换为累加树
// 递归
int addition = 0;
public TreeNode convertBST(TreeNode root) {
    if (root == null) return null;
    root.right = convertBST(root.right);
    root.val += addition;
    addition = root.val;
    root.left = convertBST(root.left);
    return root;
}
// 迭代
public TreeNode convertBST(TreeNode root) {
    if (root == null) return null;
    Stack<TreeNode> stack = new Stack<>();
    int addition = 0;
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
        if (cur != null) {
            stack.push(cur);
            cur = cur.right;
        }else {
            cur = stack.pop();
            cur.val += addition;
            addition = cur.val;
            cur = cur.left;
        }
    }
    return root;
}
六、二叉搜索树的构造与修改
1、二叉搜索树中的插入操作
// 递归
public TreeNode insertIntoBST(TreeNode root, int val) {
    if (root == null) return new TreeNode(val);
    if (root.val < val) root.right = insertIntoBST(root.right, val);
    else root.left = insertIntoBST(root.left, val);
    return root;
}
// 迭代
public TreeNode insertIntoBST(TreeNode root, int val) {
    if (root == null) return new TreeNode(val);
    TreeNode cur = root;
    TreeNode prev = root;
    while (cur != null) {
        prev = cur;
        if (cur.val < val) cur = cur.right;
        else if (cur.val > val) cur = cur.left;
    }
    if (prev.val > val) prev.left = new TreeNode(val);
    else prev.right = new TreeNode(val);
    return root;
}
2、二叉搜索树中的删除操作

删除有五种情况,需要注意这道题

public TreeNode deleteNode(TreeNode root, int key) {
    if (root == null) return root;
    if (root.val < key) root.right = deleteNode(root.right, key);
    else if (root.val > key) root.left = deleteNode(root.left, key);
    else {
        // root.val==key
        // 1、叶子节点
        // 2、左孩子为空,右孩子不为空
        // 3、右孩子为空,左孩子不为空
        if (root.left == null) return root.right;
        if (root.right == null) return root.left;

        // 4、左右孩子都不为空
        TreeNode tmp = root.right;
        while (tmp.left != null) {
            tmp = tmp.left;
        }
        tmp.left = root.left;
        return root.right;
    }
    return root;
}
3、修剪二叉搜索树
public TreeNode trimBST(TreeNode root, int low, int high) {
    if (root == null) return null;
    if (root.val < low) return trimBST(root.right, low, high);
    if (root.val > high) return trimBST(root.left, low, high);
    root.left = trimBST(root.left, low, high);
    root.right = trimBST(root.right, low, high);
    return root;
}
4、有序数组转换为二叉搜索树
public TreeNode sortedArrayToBST(int[] nums) {
    if (nums == null || nums.length == 0) return null;
    return sortedArrayToBST1(nums, 0, nums.length-1);
}
public TreeNode sortedArrayToBST1(int[] nums, int left, int right) {
    if (left > right) return null;
    int mid = left + (right - left) / 2;
    TreeNode root = new TreeNode(nums[mid]);
    root.left = sortedArrayToBST1(nums, left, mid-1);
    root.right = sortedArrayToBST1(nums, mid+1, right);
    return root;
}
5、最近公公祖先
// 递归
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
    if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
    return root;
}
// 迭代
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
    while (true) {
        if (root.val < p.val && root.val < q.val) root = root.right;
        else if (root.val > p.val && root.val > q.val) root = root.left;
        else return root;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值