一些树算法的基本功

节点定义

    public static 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;
        }
    }

带有父节点的节点定义

    public static class Node {
        int val;
        Node left;
        Node right;
        Node parent;

        public Node(int val) {
            this.val = val;
        }
    }

二叉树前中后遍历(递归版)

    /**
     * 递归版前中后遍历
     */

    //二叉树前序遍历(递归版)
    public static List<Integer> preOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        po(root, list);

        return list;
    }

    private static void po(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }

        list.add(root.val);
        po(root.left, list);
        po(root.right, list);
    }

    //二叉树中序遍历(递归版)

    public static List<Integer> inOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        io(root, list);

        return list;
    }

    private static void io(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }

        po(root.left, list);
        list.add(root.val);
        po(root.right, list);
    }


    //二叉树后序遍历(递归版)
    public static List<Integer> postOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        pso(root, list);

        return list;
    }

    private static void pso(TreeNode root, List<Integer> list) {
        if (root == null) {
            return;
        }

        po(root.left, list);
        po(root.right, list);
        list.add(root.val);
    }

二叉树前中后遍历(非递归版)

    /**
     * 非递归版前中后遍历
     */

    //二叉树前序遍历(非递归版)
    public static List<Integer> preOrder1(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        if (root == null) return list;

        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode cur = stack.pop();
            list.add(cur.val);

            if (cur.right != null) {
                stack.push(cur.right);
            }

            if (cur.left != null) {
                stack.push(cur.left);
            }
        }

        return list;
    }


    //二叉树中序遍历(非递归版)
    public static List<Integer> inOrder1(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        if (root == null) return list;

        Stack<TreeNode> stack = new Stack<>();

        while (!stack.isEmpty() || root != null) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                root = stack.pop();
                list.add(root.val);
                root = root.right;
            }
        }
        return list;
    }

    //二叉树后序遍历(非递归版)
    public static List<Integer> postOrder1(TreeNode root) {
        List<Integer> list = new ArrayList<>();

        if (root == null) return list;

        //准备两个栈 一个使用栈 一个收集栈
        Stack<TreeNode> stack1 = new Stack<>();
        Stack<TreeNode> stack2 = new Stack<>();

        stack1.push(root);
        while (!stack1.isEmpty()) {
            TreeNode cur = stack1.pop();
            stack2.push(cur);

            if (cur.left != null) {
                stack1.push(cur.left);
            }

            if (cur.right != null) {
                stack1.push(cur.right);
            }
        }

        while (!stack2.isEmpty()) {
            list.add(stack2.pop().val);
        }

        return list;
    }

判断搜索二叉树

/**
 * 如何判断一棵二叉树是否是搜索二叉树
 * (搜索二叉树中序遍历为升序排列)
 */

//方法1 利用搜索二叉树中序遍历为升序排列(递归版本)
public static boolean isBST(TreeNode root) {
    int prevalue = Integer.MIN_VALUE;

    if (root == null) {
        return true;
    }

    boolean isLeftBST = isBST(root.left);

    if (root.val <= prevalue) {
        return false;
    } else {
        prevalue = root.val;
    }

    return isBST(root.right);
}

//方法1 利用搜索二叉树中序遍历为升序排列(非递归版本)
public static boolean isBST1(TreeNode root) {
    int preValue = Integer.MIN_VALUE;

    Stack<TreeNode> stack = new Stack<>();

    while (stack != null || root != null) {
        if (root != null) {
            stack.push(root);
            root = root.left;
        } else {
            root = stack.pop();
            if (root.val <= preValue) {
                return false;
            } else {
                preValue = root.val;
            }
            root = root.right;
        }
    }
    return true;
}

//方法二:套路解题
 /*套路解题(看需要左右树的什么信息)
1.需要左树是搜索二叉树
2.需要右树是搜索二叉树
3.左树的最大值
4.右树的最小值
 */
public static class ReturnType1 {
    public boolean isBST;
    public int max;
    public int min;

    public ReturnType1(boolean isBST, int max, int min) {
        this.isBST = isBST;
        this.max = max;
        this.min = min;
    }
}

public static boolean isBST2(TreeNode root) {
    return process1(root).isBST;
}

public static ReturnType1 process1(TreeNode root) {
    if (root == null) {
        return null;
    }

    ReturnType1 leftType = process1(root.left);
    ReturnType1 rightType = process1(root.right);


    int max = root.val;
    int min = root.val;

    if (leftType != null) {
        min = Math.min(min, leftType.min);
        max = Math.max(max, leftType.max);
    }

    if (rightType != null) {
        min = Math.min(min, rightType.min);
        max = Math.max(max, rightType.max);
    }

    boolean isBST = true;
    if (leftType != null && (leftType.isBST || leftType.max >= root.val)) {
        isBST = false;
    }
    if (rightType != null && (rightType.isBST || rightType.min <= root.val)) {
        isBST = false;
    }

    return new ReturnType1(isBST, min, max);

}

判断完全二叉树

    /**
     * 如何判断一棵二叉树是否是完全二叉树(BFS )
     */
    /*1.任一节点 有右无左返回false;
      2.在1不违规的前提下,如果遇到第一个左右不双全的节点,后续皆是叶子节点*/
    public static boolean isCBT(TreeNode root) {
        if (root == null) return true;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);

        //定义一个标志位 专门看是否已经碰到过左右不双全的节点
        Boolean leaf = false;
        TreeNode l;
        TreeNode r;

        while (queue != null) {
            TreeNode cur = queue.poll();
            l = cur.left;
            r = cur.right;

            if (
                    (leaf && (l != null || r != null))
                            ||
                            (l == null && r != null)
            ) {
                return false;
            }

            if (l != null) {
                queue.add(cur.left);
            }

            if (r != null) {
                queue.add(cur.right);
            }

            if (l == null || r == null) {
                leaf = true;
            }
        }

        return true;
    }

判断满二叉树

    /**
     * 如何判断一棵二叉树是否是满二叉树(BFS)
     */
    /*套路解题(看需要左右树的什么信息)
    1.需要左树是满二叉树
    2.需要右树是满二叉树
     */

    public static class ReturnType2 {
        public int height;
        public int nodes;

        public ReturnType2(int height, int nodes) {
            this.height = height;
            this.nodes = nodes;
        }
    }

    public boolean isFull(TreeNode root) {
        return process2(root).nodes == Math.pow(2, process2(root).height);
    }

    public ReturnType2 process2(TreeNode root) {
        if (root == null) {
            return new ReturnType2(0, 0);
        }

        ReturnType2 leftType = process2(root.left);
        ReturnType2 rightType = process2(root.right);

        int height = Math.max(leftType.height, rightType.height) + 1;
        int nodes = leftType.nodes + rightType.nodes + 1;

        return new ReturnType2(height, nodes);


    }

判断平衡二叉树


    /**
     * 如何判断一棵二叉树是否是平衡二叉树
     */
    /*套路解题(看需要左右树的什么信息)
    1.需要左树是平衡二叉树
    2.需要右树是平衡二叉树
    3.需要|左树高度-右树高度<=1|
     */
    public static class ReturnType {
        public boolean isBalanced;
        public int height;

        public ReturnType(boolean isBalanced, int height) {
            this.isBalanced = isBalanced;
            this.height = height;
        }
    }

    public static boolean isBalanced(TreeNode root) {
        return process(root).isBalanced;
    }

    private static ReturnType process(TreeNode root) {
        if (root == null) {
            return new ReturnType(true, 0);
        }

        ReturnType leftType = process(root.left);
        ReturnType rightType = process(root.right);

        int height = Math.max(leftType.height, rightType.height) + 1;

        boolean isBalanced = leftType.isBalanced && rightType.isBalanced &&
                Math.abs(leftType.height - rightType.height) <= 1;

        return new ReturnType(isBalanced, height);
    }

寻找最小公共祖先

    /**
     * 寻找最小公共祖先
     */
    //方法1:将两节点的向上链都表示出来
    public static TreeNode lca1(TreeNode root, TreeNode node1, TreeNode node2) {
        HashMap<TreeNode, TreeNode> fatherMap = new HashMap<>();
        fatherMap.put(root, root);
        process3(root, fatherMap);

        HashSet<TreeNode> set = new HashSet<>();

        TreeNode cur = node1;
        while (cur != fatherMap.get(cur)) {
            set.add(cur);
            cur = fatherMap.get(cur);
        }

        set.add(root);

        cur = node2;
        while (cur != fatherMap.get(cur)) {
            if (set.contains(cur)) {
                return cur;
            }
            cur = fatherMap.get(cur);
        }
        return root;
    }

    public static void process3(TreeNode root, HashMap<TreeNode, TreeNode> fatherMap) {
        if (root == null) {
            return;
        }

        fatherMap.put(root.left, root);
        fatherMap.put(root.right, root);
        process(root.left);
        process(root.right);
    }

    //方法2
    /*只有这两种情况
    1.node1 是 node2 的lca 或 node2 是 node1 的lca
    2.node1 和 node2 不互为lca
    * */
    public static TreeNode lca2(TreeNode root, TreeNode node1, TreeNode node2) {
        if (root == null || root == node1 || root == node2) {
            return root;
        }

        TreeNode left = lca2(root.left, node1, node2);
        TreeNode right = lca2(root.right, node1, node2);
        if (left != null && right != null) {
            return root;
        }

        return left != null ? left : right;
    }

寻找后继节点

    /**
     * 寻找后继节点
     */
    public static Node getSuccessorNode(Node node) {
        if (node == null) {
            return node;
        }

        if (node.right != null) {
            return getLeftMost(node.right);
        } else {
            Node parent = node.parent;
            while (parent != null && parent.left != node) {
                node = parent;
                parent = node.parent;
            }
            return parent;
        }
    }

    private static Node getLeftMost(Node node) {
        if (node == null) {
            return node;
        }
        while (node.left != null) {
            node = node.left;
        }

        return node;
    }
/**
 * 序列化与反序列化
 */

 public static void main(String[] args) {
     TreeNode treeNode7 = new TreeNode(7);
     TreeNode treeNode6 = new TreeNode(6);
     TreeNode treeNode5 = new TreeNode(5);
     TreeNode treeNode4 = new TreeNode(4);
     TreeNode treeNode3 = new TreeNode(3, treeNode6, treeNode7);
     TreeNode treeNode2 = new TreeNode(2, treeNode4, treeNode5);
     TreeNode treeNode1 = new TreeNode(1, treeNode2, treeNode3);

     List<Integer> list = inOrder1(treeNode1);
     for (Integer i :
             list) {
         System.out.println(i);
     }


     System.out.println(isBST(treeNode1));
 }

}

猜你喜欢

转载自blog.csdn.net/Wantbebetter/article/details/121479113