面试常见的二叉树问题

来源:互联网 发布:spss输入数据是问号 编辑:程序博客网 时间:2024/06/03 11:19
package 算法和数据结构;/*** Filename : BinarySearchTree.java* Author : zhihao_tian@126.com* Creation time : 下午6:26:50 - 2017年3月11日* Description :*/import java.util.Stack;public class BinarySearchTree {/* * 面试中常见的二叉搜索树的问题 */    public class BinaryTreeNode<E> {        E element;        BinaryTreeNode<E> left;        BinaryTreeNode<E> right;        public BinaryTreeNode(E e) {            element = e;        }        public BinaryTreeNode() {        }    }     /*     * 求二叉树中节点的个数     * 递归解法:     * 1.如果二叉树为空,返回0     * 2.如果二叉树部位空,返回  左子树节点个数+右子树节点个数+1     */    int getNodeNum(BinaryTreeNode root){        if (root == null)            return 0;        else             return getNodeNum(root.left)+getNodeNum(root.right)+1;    }   /*    * 求二叉树的深度    * 递归解法:    * 1.如果二叉树为空,则二叉树的深度为0    * 2.否则,二叉树的深度 = max(左子树深度,右子树深度)+1    */    int getDepth(BinaryTreeNode root) {        if (root == null)            return 0;        else             return Math.max(getDepth(root.left), getDepth(root.right))+1;    }   /*    * 二叉树的前序中序后序遍历    * 递归解法    */    void preOrderTraverse(BinaryTreeNode root) {        if(root == null)            return;        System.out.print(root.element);        preOrderTraverse(root.left);        preOrderTraverse(root.right);    }    void inOrderTraverse(BinaryTreeNode root) {        if( root == null)            return;        inOrderTraverse(root.left);        System.out.print(root.element);        inOrderTraverse(root.right);    }    void postOrderTraverse(BinaryTreeNode root) {        if(root == null)            return;        postOrderTraverse(root.left);        postOrderTraverse(root.right);        System.out.print(root.element);    }    /*     * 分层遍历二叉树(从左至右,从上到下)BFS     * 相当于广度优先搜索,使用队列实现。     * 队列初始化,将根节点压入队列。当队列部位空的时候进行如下操作:     * 弹出一个节点,访问,若左子树或右子树不为空,则将其压入队列     */    void levelTraverse(BinaryTreeNode root) {        if(root == null)            return;        java.util.Queue<BinaryTreeNode> queue =                 new java.util.LinkedList<BinaryTreeNode>();        queue.offer(root);        while(!queue.isEmpty()) {            BinaryTreeNode node = queue.peek();            queue.poll();            System.out.print(node.element);            if(node.left != null){                queue.offer(node.left);            }            if(node.right != null) {                queue.offer(node.right);            }        }    }    /*     * 二叉树的深度优先搜索,DFS,相当于非递归实现二叉树的先序遍历     * 将根节点压入栈中,如果栈不为空:先访问栈顶元素,在pop,如果栈顶元素有左子树,将     * 左子树压入栈,如果右子树不为空,则压入右子树。     */    void deepFirstSearch(BinaryTreeNode root) {        if(root == null)             return;        Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();        stack.push(root);        BinaryTreeNode node = new BinaryTreeNode();        while(!stack.isEmpty()) {            node = stack.peek();            System.out.print(node.element);            stack.pop();            if(node.left!=null){                stack.push(node.left);            }            if(node.right != null) {                stack.push(node.right);            }        }    }    /*     * 将二叉树变为有序的双向链表     */    /*     * 求二叉树的叶节点个数     * 递归解法:     * 1.如果二叉树为空,或者K<1,返回0     * 2.如果二叉树部位空而左右子树为空,则返回1;     * 3.如果二叉树不为空,且左右子树不同是为空,则返回左子树叶节点个数加上右子树叶节点的个数     */    int getLeafNodeNum(BinaryTreeNode root) {        if(root == null)            return 0;        else if((root.left == null) && (root.right == null))            return 1;        int leftNum = getLeafNodeNum(root.left);        int rightNum = getLeafNodeNum(root.right);        return (leftNum + rightNum);    }    /*     * 求二叉树第K层节点的个数     * 递归解法:     * 1.若二叉树为空或者K<1则返回0     * 2.若二叉树不为空,K=1则返回1     * 3.若二叉树不为空且k>1,返回左子树中第K-1层节点个数加上右子树第K-1层节点的个数     */    int getKthLevelNodeNum(BinaryTreeNode root,int k) {        if (root == null|| k < 1)            return 0;        if(k == 1)            return 1;        int numleft = getKthLevelNodeNum( root.left, k - 1);        int numright = getKthLevelNodeNum( root.right, k - 1);        return (numleft + numright);    }    /*     * 判断两棵树结构是否相同     * 递归求解:     * 1.如果两棵树都为空,返回真     * 2.如果有一颗为空另一颗不为空,则返回假     * 3.如果两棵树都不为空,如果对应的左右子树都同构,则返回真,否则返回假     */    boolean structureCmp(BinaryTreeNode root1,BinaryTreeNode root2) {        if(root1 == null && root2 == null)            return true;        else if(root1 == null || root2 == null)            return false;        boolean leftRes = structureCmp(root1.left,root2.left);        boolean rightRes = structureCmp(root1.right,root2.right);        return(leftRes && rightRes);    }    /*     * 判断二叉树是不是平衡二叉树     * 递归解法:     * 1.如果二叉树为空,返回真     * 2.如果二叉树不为空,如果左子树和右子树都是AVL树,并且左子树和右子树的高对差不超过1     * 则返回真,其他返回假     */    boolean isAVL(BinaryTreeNode root, int height) {        if(root == null){            height = 0;            return true;        }        int heightLeft = getDepth(root.left);        boolean resLeft = isAVL(root.left,heightLeft);        int heightRight = getDepth(root.right);        boolean resRight = isAVL(root.right,heightRight);        if(resLeft&&resRight&&(Math.abs(heightLeft - heightRight)<=1)){            height = Math.max(heightLeft,heightRight)+1;            return true;        }        else {            height = Math.max(heightLeft, heightRight)+1;            return false;        }    }    /*     * 求二叉树中两个节点的最低公共祖先节点     * 递归求解     * 1.如果两个节点分别在根节点的左子树和右子树,则返回根节点     * 2.如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树     */    boolean FindNode(BinaryTreeNode pRoot, BinaryTreeNode pNode)    {        if(pRoot == null || pNode == null)            return false;        if(pRoot == pNode)            return true;        boolean found = FindNode(pRoot.left, pNode);        if(!found)            found = FindNode(pRoot.right, pNode);        return found;    }    BinaryTreeNode GetLastCommonParent(BinaryTreeNode pRoot,                                          BinaryTreeNode  pNode1,                                          BinaryTreeNode  pNode2)    {        if(FindNode(pRoot.left, pNode1))        {            if(FindNode(pRoot.right, pNode2))                return pRoot;            else                return GetLastCommonParent(pRoot.left, pNode1, pNode2);        }        else        {            if(FindNode(pRoot.left, pNode2))                return pRoot;            else                return GetLastCommonParent(pRoot.right, pNode1, pNode2);        }    }    /*     * 上述递归解法效率很低,有很多重复的遍历,下面看一下非递归解法。     * 非递归解法:     * 先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点也就是他们在二叉树中的     * 最低公共祖先节点     */public boolean findPath(TreeNode root, TreeNode node, ArrayList<TreeNode> path) {    if(root==null || node==null){        return false;    }    path.add(root);    if (root.val == node.val)        return true;    if(findPath(root.left, node, path)){        return true;    }    if(findPath(root.right, node, path)){        return true;    }    path.remove(path.size() - 1);    return false;} public TreeNode GetLastCommonParent2(TreeNode root, TreeNode node1, TreeNode node2) {    ArrayList<TreeNode> path1 = new ArrayList<>();    ArrayList<TreeNode> path2 = new ArrayList<>();    findPath(root, node1, path1);    findPath(root, node2, path2);    if(path1.size()==0 || path2.size()==0)          return null;      int len=path1.size()<path2.size()?path1.size():path2.size();      for(int i=0;i<len;i++){          if(path1.get(i).data.equals(path2.get(i).data)){              parent=path1.get(i);          }      }      return parent;  }    /*     * 求二叉树中节点的最大距离     * 递归解法:     * 1.如果二叉树为空,返回0,同时记录左子树和右子树的深度,都为0     * 2.如果二叉树不为空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,     * 要么是左子树节点中到根节点的最大距离+右子树节点     * 中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。     */    int GetMaxDistance(BinaryTreeNode pRoot, int maxLeft, int maxRight)    {        // maxLeft, 左子树中的节点距离根节点的最远距离        // maxRight, 右子树中的节点距离根节点的最远距离        if(pRoot == null)        {            maxLeft = 0;            maxRight = 0;            return 0;        }        int maxLL = getDepth(pRoot.left.left);        int maxLR = getDepth(pRoot.left.right);        int maxRL = getDepth(pRoot.right.left);        int maxRR = getDepth(pRoot.right.right);        int maxDistLeft, maxDistRight;        if(pRoot.left!= null)        {            maxDistLeft = GetMaxDistance(pRoot.left, maxLL, maxLR);            maxLeft = Math.max(maxLL, maxLR) + 1;        }        else        {            maxDistLeft = 0;            maxLeft = 0;        }        if(pRoot.right!= null)        {            maxDistRight = GetMaxDistance(pRoot.right, maxRL, maxRR);            maxRight = Math.max(maxRL, maxRR) + 1;        }        else        {            maxDistRight = 0;            maxRight = 0;        }        return Math.max(Math.max(maxDistLeft, maxDistRight), maxLeft+maxRight);    }    /*     * 判断二叉树是不是完全二叉树     * 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中     * 在最左边,这就是完全二叉树     * 有如下算法,按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,则该节点右子树必须为空,     * 且后面遍历的节点左右子树都必须为空,否则不是完全二叉树。     */    boolean IsCompleteBinaryTree(BinaryTreeNode  pRoot)    {        if(pRoot == null)            return false;        java.util.Queue<BinaryTreeNode> q = new java.util.LinkedList<BinaryTreeNode>() ;        q.offer(pRoot);        boolean mustHaveNoChild = false;        boolean result = true;        while(!q.isEmpty())        {            BinaryTreeNode pNode = q.peek();            q.poll();            if(mustHaveNoChild) // 已经出现了有空子树的节点了,后面出现的必须为叶节点(左右子树都为空)            {                if(pNode.left != null || pNode.right != null)                {                    result = false;                    break;                }            }            else            {                if(pNode.left != null && pNode.right != null)                {                    q.offer(pNode.left);                    q.offer(pNode.right);                }                else if(pNode.left != null && pNode.right == null)                {                    mustHaveNoChild = true;                    q.offer(pNode.left);                }                else if(pNode.left == null && pNode.right != null)                {                    result = false;                    break;                }                else                {                    mustHaveNoChild = true;                }            }        }        return result;    }}
0 0