面试常见的二叉树问题
来源:互联网 发布: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
- 面试常见的二叉树问题
- 面试常见二叉树问题
- 面试中常见的二叉树问题_world
- 常见的面试问题
- 常见的面试问题
- 常见的面试问题
- 面试常见的问题
- 面试中关于二叉树的常见习题(持续更新)
- 二叉树的一些笔试面试常见题目
- 二叉树遍历-面试常见题
- 转 面试中的常见二叉树题目
- 二叉树笔试面试常见算法题
- ABAPER面试常见的问题
- 常见的英文面试问题
- C# 常见的面试问题
- 面试中常见的问题
- iOS面试常见的问题
- 常见的面试C++问题
- xgboost使用小结
- Android 状态保存与恢复流程 完全解析
- BZOJ 4010 [HNOI2015]菜肴制作 拓扑排序
- 逻辑推理
- bzoj刷题记录5.11-5.15
- 面试常见的二叉树问题
- 走格子问题
- 38题 循环嵌套
- 堆排序
- Boolan* C++课程第四周笔记
- python中常见的数据预处理方法
- 1099 字串变换
- ElasticsearchCRUD使用(六)【EF和Elasticsearch的MVC应用程序】
- React Native导航器之react-navigation使用