Java二叉树

目录

    • 1.二叉树的概念与性质
    • 2.二叉树的递归遍历
      • 2.1 前序遍历(根左右)
      • 2.2 中序遍历(左根右)
      • 2.3 后序遍历(左右根)
    • 3.二叉树的非递归遍历
      • 3.1 前序遍历(栈)
      • 3.2 中序遍历(栈)
      • 3.3 后序遍历(栈)
    • 4.二叉树的层序遍历(队列)
    • 5.模拟实现二叉树的操作【子问题思想】
      • 5.1 获取树的节点数(左树结点数+右树结点数+1)
      • 5.2 获取叶子节点的个数(左边叶子结点数+右边叶子节点数)
      • 5.3 获取第K层节点的个数(左树的第k-1层的节点数+右树的第k-1层的节点数)
      • 5.4 获取二叉树的高度(左右子树高度的最大值+1)
      • 5.5 检测值为value的元素是否存在(根左右遍历判断)
      • 5.6 判断是否为完全二叉树(队列)

1.二叉树的概念与性质

  1. 树是一种非线性的数据结构,树是递归定义的,一颗N个结点的树有N-1条边。
  2. 二叉树根结点所在的层为第1层,那么第i层的节点数为2的i-1次方个。
  3. 深度为k的二叉树,总的节点数为2的k次方-1个。推导方法为:等比数列求和。
  4. 由深度为k的总结点数,可以推导出深度k为log(n+1)向上取整。
  5. 对于任何一颗二叉树,n0=n2+1。
    推导:**(边相等原则)**树的总节点数为n0+n1+n2
    那么树的边为n0+n1+n2-1以及2*n2+n1。
    度为2的节点产生2条边,度为1的产生1条边
    一颗N个节点的树有N-1条边

    两式相等得:n0=n2+1
  6. 若已知双亲结点序号为i,则其若有左孩子和右孩子。那么左孩子的结点序号为2i+1,右孩子的结点序号2i+2。
    若已知孩子结点的序号为i,那么双亲结点的序号为(i-1)/2。
  7. 完全二叉树和满二叉树:满二叉树是一颗特殊的完全二叉树。满二叉树就是每层的节点数都达到最大值。
  8. 树的表示——孩子表示法,3个域,值、左孩子和右孩子。

2.二叉树的递归遍历

2.1 前序遍历(根左右)

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        //把root加进来
        list.add(root.val);
        List<Integer> leftTree = preorderTraversal(root.left);
        list.addAll(leftTree);
        List<Integer> rightTree = preorderTraversal(root.right);
        list.addAll(rightTree);
        return list;
    }
}

2.2 中序遍历(左根右)

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        List<Integer> leftTree = inorderTraversal(root.left);
        list.addAll(leftTree);
        list.add(root.val);
        List<Integer> rightTree = inorderTraversal(root.right);
        list.addAll(rightTree);
        return list;
    }
}

2.3 后序遍历(左右根)

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        List<Integer> leftTree = postorderTraversal(root.left);
        list.addAll(leftTree);
        List<Integer> rightTree = postorderTraversal(root.right);
        list.addAll(rightTree);
        list.add(root.val);
        return list;
    }
}

3.二叉树的非递归遍历

3.1 前序遍历(栈)

思路:
Java二叉树_第1张图片
代码:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Deque<TreeNode> stack = new ArrayDeque<>();
        TreeNode cur = root;
        while (!stack.isEmpty() || cur != null )  {
            while (cur != null) {
                stack.push(cur);
                list.add(cur.val);
                cur = cur.left;
            }
            if(cur == null) {
                cur = stack.pop().right;
            }
        }
        return list;
    }
}

3.2 中序遍历(栈)

思路:
Java二叉树_第2张图片

代码:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            if (cur == null) {
                TreeNode top = stack.pop();
                list.add(top.val);
                cur = top.right;
            }
        }
        return list;
    }
}

3.3 后序遍历(栈)

思路:后序遍历要记录prev弹出的结点,避免陷入循环
Java二叉树_第3张图片

代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if (root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode pre = null;
        while (cur != null || !stack.isEmpty()) {
            while (cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.peek();

            if (top.right == null || top.right == pre) {
                pre = stack.pop();
                list.add(pre.val);
            }else {
                cur = top.right;
            }
        }
        return list;
    }
}

4.二叉树的层序遍历(队列)

力扣102. 二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

思路:

代码:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> list = new ArrayList<>();
        if(root == null) {
            return list;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            List<Integer> tmp = new ArrayList<>();
            int size = queue.size();
            while (size != 0){
                TreeNode front = queue.poll();
                tmp.add(front.val);
                size--;
                if (front.left != null) {
                    queue.offer(front.left);
                }
                if (front.right != null) {
                    queue.offer(front.right);
                }   
            }
            list.add(tmp);
        }
        return list;
    }
}

扩展:打印二叉树的左视图
在上述list中通过get方法得到每个tmp的首元素,即list.get(i).get(0),得到的打印结果为二叉树的左视图。

5.模拟实现二叉树的操作【子问题思想】

5.1 获取树的节点数(左树结点数+右树结点数+1)

思路:总的节点数=树的左边节点数+树的右边节点数+自己1

    int size(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftSize = size(root.left);
        int rightSize = size(root.right);
        return leftSize + rightSize + 1;
    }

5.2 获取叶子节点的个数(左边叶子结点数+右边叶子节点数)

思路:树的叶子节点数=左边叶子结点数+右边叶子节点数
Java二叉树_第4张图片

    // 获取叶子节点的个数
    int getLeafNodeCount(TreeNode root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        int leftLeaf = getLeafNodeCount(root.left);
        int rightLeaf = getLeafNodeCount(root.right);
        return leftLeaf + rightLeaf;
    }

5.3 获取第K层节点的个数(左树的第k-1层的节点数+右树的第k-1层的节点数)

思路:当k为1,且结点不为空的时候就加1。最后一层相对与根是第k层,但是相对于根的下一层是k-1层,相对于自己是第1层。
比如求第3层的节点数:一开始root==‘4’, k=3,则执行root==‘2’,k=2;则执行root=‘1’,k=1,此时返回1;则执行root=‘3’,k=1,此时返回1。因此root==‘2’的时候返回2,依次类推。
Java二叉树_第5张图片

    // 获取第K层节点的个数
    int getKLevelNodeCount(TreeNode root,int k) {
        if (root == null) {
            return 0;
        }
        if (k == 1) {
            return 1;
        }
        int left = getKLevelNodeCount(root.left,k-1);
        int right = getKLevelNodeCount(root.right,k-1);
        return left+right;
    }

5.4 获取二叉树的高度(左右子树高度的最大值+1)

思路:左树的高度和右数的高度求最大值再+1
注意最好把递归的高度给算出来赋值给leftHigh 和righttHigh ,否则会造成递归重复计算,以至于栈溢出超出时间限制。(力扣104. 二叉树的最大深度)

    // 获取二叉树的高度
    int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHigh = getHeight(root.left);
        int righttHigh = getHeight(root.right);
        return leftHigh > righttHigh ? leftHigh + 1 : righttHigh + 1;
    }

5.5 检测值为value的元素是否存在(根左右遍历判断)

思路:先看根,再看左,再看右(遍历);如果左边返回的不为空,那么就存在,如果右边的返回值不为空,【注意递归要拿返回值来接受】,那么存在,如果左边也没找到,右边也没找到那么不存在返回空。不管怎么样,在根的左边会有一个返回值null or val,如果不为空那么函数就结束,在根的右边也是如此。
易错点:递归没有接受其返回值,并且进行判断。

    // 检测值为value的元素是否存在
    TreeNode find(TreeNode root, int val) {
        if (root == null) {
            return null;
        }
        if (root.val == val) {
            return root;
        }
        TreeNode leftVal = find(root.left,val);
        if (leftVal != null) {
            return leftVal;
        }
        TreeNode rightVal = find(root.right,val);
        if (rightVal != null) {
            return rightVal;
        }
        return null;
    }

5.6 判断是否为完全二叉树(队列)

思路:每次从队列中取出一个结点,如果这个结点不为空,就把其左孩子和右孩子入队,如果这个结点为空,则直接跳出判断队列中现有的元素是否有为空的,如果有则说明不是完全二叉树,如果都不为空则说明是完全二叉树。
代码:

    boolean isCompleteTree(TreeNode root) {
        if (root == null) {
            return true;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode top = queue.poll();
            if (top != null) {
                queue.offer(top.left);
                queue.offer(top.right);
            }else {
                break;
            }
        }
        while (!queue.isEmpty()) {
            TreeNode top = queue.poll();
            if (top == null) {
                return false;
            }
        }
        return true;
    }

你可能感兴趣的:(Java数据结构,java,算法,leetcode)