剑指offer39 平衡二叉树


剑指offer

39 平衡二叉树

题目描述

输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

输入

{1,2,3,4,5,6,7}

输出

true

思路(递归)

从下往上遍历,如果子树是平衡二叉树,则返回子树的高度;如果发现子树不是平衡二叉树,则直接停止遍历,这样至多只对每个结点访问一次。

代码

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return TreeDepth(root) != -1; 
    }

    public static int TreeDepth(TreeNode root){
        if(root==null)return 0;

        //递归
        int depleft = TreeDepth(root.left);
        if(depleft==-1) return -1;    //如果递归完左子树,发现左子树不满足平衡二叉树,则返回 -1;右子树同理
        int depright = TreeDepth(root.right);
        if(depright==-1) return -1;
        return Math.abs(depleft-depright)>1 ? -1 : 1 + Math.max(depleft,depright);    //记得加上根节点的1
    }
}

补充:二叉树的创建、遍历、深度、宽度

其中,遍历包括 先序、中序、后序、层次,每一种都采用递归和非递归方法实现。

二叉树创建

采用 动态代理 方便输出,注意以下三点:

  • 一个方法不能修改一个基本数据类型的参数
  • 一个方法可以修改一个对象参数的状态
  • 一个方法不能实现让对象参数引用一个新对象(这句话在这里尤为适用)

遍历

  • 前序、中序、后序非递归遍历采用栈辅助实现
  • 层次非递归遍历采用队列实现

代码

AbstractBinaryTree.interface

public interface AbstractBinaryTree {

    void printPostOder();

    void printPostOderByRecursion();

    void printPreOder();

    void printPreOderByRecursion();

    void printInOderByRecursion();

    void printInOder();

    void printHeight();

    void printMaxWidth();

    void printLevelOrder();

}

BinaryTree.java

package test.tree;

/**
 * 为了方便展示,并没有将Node属性私有
 */

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/**
 * 为了方便展示,并没有将Node属性私有
 */

class Node {

    public String data;
    public Node left = null;
    public Node right = null;
    public boolean flag;

    Node(String data) {
        this.data = data;
    }

    Node() {
    }

    @Override
    public String toString() {

        return this.data;
    }

}



public class BinaryTree implements AbstractBinaryTree{

    private Node root = new Node();

    public Node getRoot() {
        return root;
    }

    public void printNode(Node node) {

        if (node.data == null) {
            System.out.print("");
        } else {
            System.out.print(node.data);
        }
    }

    public BinaryTree(String tree) {
        String[] treeNodes = tree.split(",");
        createTreeByRecursion(treeNodes);
    }

    private int createTreeByRecursion(Node node, String[] treeNodes, int n) {

        if ("#".equals(treeNodes[n]))
            return n + 1;

        node.data = treeNodes[n];

        node.left = new Node();
        int left = createTreeByRecursion(node.left, treeNodes, n + 1);

        node.right = new Node();
        int right = createTreeByRecursion(node.right, treeNodes, left);

        return right;
    }

    public void createTreeByRecursion(String[] treeNodes) {
        createTreeByRecursion(root, treeNodes, 0);
    }

    /**
     * 先序非递归创建
     */
    public void createTree(String[] treeNodes) {

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

        int index = 0;

        Node node = root;

        while (index < treeNodes.length) {

            while (true) {

                if ("#".equals(treeNodes[index])) {

                    node = stack.pop();

                    if (node.flag == false) {
                        node.left = null;
                        node.flag = true;
                        stack.push(node);
                    } else {
                        node.right = null;
                    }

                    // 记得加1
                    index++;
                    break;
                }

                if (node.flag == true) {
                    node.right = new Node();
                    node = node.right;
                }

                node.data = treeNodes[index];
                stack.push(node);
                node.left = new Node();
                node = node.left;
                index++;
            }

            if (node.flag == false) {
                stack.push(node);
                node.flag = true;
                node = node.right;
            } else {
                node = stack.peek();
                node.flag = true;
            }

        }

    }

    // 递归调用的方法,需要将root传递进去
    //递归, 先序遍历
    private void printPreOderByRecursion(Node node) {

        if (node == null)
            return;

        printNode(node);
        printPreOderByRecursion(node.left);
        printPreOderByRecursion(node.right);

    }

    public void printPreOderByRecursion() {

        printPreOderByRecursion(root);
    }

    //递归, 中序遍历
    private void printInOderByRecursion(Node node) {

        if (node == null)
            return;

        printInOderByRecursion(node.left);
        printNode(node);
        printInOderByRecursion(node.right);

    }

    public void printInOderByRecursion() {
        printInOderByRecursion(root);
    }

    //递归, 后序遍历
    private void printPostOderByRecursion(Node node) {

        if (node == null)
            return;

        printPostOderByRecursion(node.left);
        printPostOderByRecursion(node.right);
        printNode(node);

    }

    public void printPostOderByRecursion() {

        printPostOderByRecursion(root);
    }

    // 非递归遍历二叉树

    // 先序遍历
    public void printPreOder() {

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

        Node tempNode = root;

        while (true) {

            while (tempNode != null) {
                printNode(tempNode);
                stack.push(tempNode);
                tempNode = tempNode.left;
            }

            if (stack.isEmpty()) {
                break;
            }

            tempNode = stack.pop();
            tempNode = tempNode.right;

        }

    }

    // 中序遍历
    public void printInOder() {

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

        Node tempNode = root;

        while (true) {

            while (tempNode != null) {
                stack.push(tempNode);
                tempNode = tempNode.left;
            }

            if (stack.isEmpty()) {
                break;
            }
            tempNode = stack.pop();
            printNode(tempNode);
            tempNode = tempNode.right;

        }

    }

    // 后序遍历
    public void printPostOder() {

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

        Node tempNode = root;

        while (true) {

            while (tempNode != null) {
                if (tempNode.flag == true) {
                    tempNode = tempNode.right;
                } else {
                    stack.push(tempNode);
                    tempNode = tempNode.left;
                }

            }

            tempNode = stack.pop();

            if (tempNode.flag == false) {
                stack.push(tempNode);
                tempNode.flag = true;
                tempNode = tempNode.right;
            } else {
                printNode(tempNode);
                if (stack.isEmpty()) {
                    break;
                }
                tempNode = stack.peek();
                tempNode.flag = true;
            }

        }

    }

    // 层序遍历 利用队列
    public void printLevelOrder() {

        Queue<Node> queue = new LinkedList<>();

        Node tempNode = root;

        queue.offer(tempNode);

        while (!queue.isEmpty()) {

            Node topNode = queue.poll();

            if (topNode == null)
                continue;

            printNode(topNode);
            queue.offer(topNode.left);
            queue.offer(topNode.right);

        }

    }

    // 树高    递归,分别求出左子树的深度、右子树的深度,两个深度的较大值+1
    public int getHeightByRecursion(Node node) {

        if (node == null) {
            return 0;
        }
        int left = getHeightByRecursion(node.left);
        int right = getHeightByRecursion(node.right);
        return 1 + Math.max(left, right);

    }

    /**
     * 为什么不直接写成调用 root,而是另写一个方法去调用呢 因为,这样可以不再为root,单独设置一个临时变量去存贮
     * 而且也固定外部调用的方法,而不用关心内部的实现
     */

    public void printHeight() {

        int height = getHeightByRecursion(root);

        System.out.print(height);
    }

    // 利用层序遍历,得到树的最大宽度
    public void printMaxWidth() {

        Queue<Node> queue = new LinkedList<>();
        Queue<Node> queueTemp = new LinkedList<>();

        int maxWidth = 1;

        Node tempNode = root;

        queue.offer(tempNode);

        while (!queue.isEmpty()) {

            while (!queue.isEmpty()) {

                Node topNode = queue.poll();

                if (topNode == null)
                    continue;

                if (topNode.left.data != null) {

                    queueTemp.offer(topNode.left);
                }

                if (topNode.right.data != null) {

                    queueTemp.offer(topNode.right);
                }

            }

            maxWidth = Math.max(maxWidth, queueTemp.size());
            queue = queueTemp;
            queueTemp = new LinkedList<>();
        }

        System.out.print(maxWidth);
    }

}

BinaryTreeTest

package test.tree;

import java.lang.reflect.Proxy;

public class BinaryTreeTest {

    public static void main(String[] args) {
        String treeStr = "1,2,3,4,5,#,#,#,#,6,#";

        AbstractBinaryTree binaryTree =  BinaryTreeTest.proxyBinaryTree(treeStr);

        binaryTree.printPreOder();
        binaryTree.printPreOderByRecursion();
        binaryTree.printInOderByRecursion();
        binaryTree.printInOder();
        binaryTree.printPostOder();
        binaryTree.printPostOderByRecursion();
        binaryTree.printLevelOrder();
        binaryTree.printHeight();
        binaryTree.printMaxWidth();
    }

    public static AbstractBinaryTree proxyBinaryTree(String treeStr) {

        AbstractBinaryTree binaryTree = new BinaryTree(treeStr);

        Object newProxyInstance = Proxy.newProxyInstance(binaryTree.getClass().getClassLoader(),
                binaryTree.getClass().getInterfaces(), (proxy, method, args) -> {
                    System.out.println(method.getName());
                    Object invoke = method.invoke(binaryTree, args);
                    System.out.println();
                    return invoke;
                });

        return (AbstractBinaryTree) newProxyInstance;
    }

}

文章作者: Hailong Gao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hailong Gao !
评论
  目录