摘要:
今天翻到了《剑指offer》面试题39,题目二中的解法二是在函数的参数列表中通过指针的方式进行传值,而java是没有指针的,所以函数要进行改造。然而我翻了下别人的java版本(我就想看看有什么高大上的改造,毕竟要传递多个参数,是不是会涉及到那么一点点设计模式呢?),简直不能忍了,我只能用一句话形容:“一本正经的胡说八道”,不过我就是喜欢看你胡说八道还迷之自信的样子。
下面吐槽一下这个版本的java代码:
1 //高效率的判断是否是一棵平衡二叉树 2 public boolean isBalanced2(BinaryTreeNode root){ 3 int depth = 0; 4 return isBalanced2(root,depth); 5 } 6 public boolean isBalanced2(BinaryTreeNode root,int depth){ 7 if(root == null){ 8 depth = 0; 9 return true; 10 } 11 int left = 0,right = 0; 12 if(isBalanced2(root.leftNode,left) && isBalanced2(root.rightNode,right)){ 13 int diff = left-right; 14 if(diff <= 1 && diff >= -1){ 15 depth = 1+(left > right?left : right); 16 return true; 17 } 18 } 19 return false; 20 }
这个文章的原始链接我就不发了,保留一点人品。关键是特么CSDN竟然把他作为百度搜索第一条置顶了,可见人气是最高的,看看作者发帖历史(好像还有那么一点小屌),我TM差点就信了。这个哥们连函数参数的复制传值都不懂啊!怎么学的编程,还发帖误导广大小学生,简直不能忍。我看也不用参考别人的代码了,自己写一个吧。
原题一:输入一颗二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根,叶子结点)形成一条路径,最长路径的长度为树的深度。
输入样例:
1
2 3
4 5 6
7
源代码:
class BinaryTreeNode{ public int data; public BinaryTreeNode left; public BinaryTreeNode right; public BinaryTreeNode(){ data = 0; left = null; right = null; } } public class Question_39 { //----递归求二叉树深度---- public static int treeDepth(BinaryTreeNode root){ if(root == null){ return 0; } int left = treeDepth(root.left); int right = treeDepth(root.right); return (left>right)?(left+1):(right+1); } public static void main(String[] args) { // TODO Auto-generated method stub BinaryTreeNode node1 = new BinaryTreeNode(); BinaryTreeNode node2 = new BinaryTreeNode(); BinaryTreeNode node3 = new BinaryTreeNode(); BinaryTreeNode node4 = new BinaryTreeNode(); BinaryTreeNode node5 = new BinaryTreeNode(); BinaryTreeNode node6 = new BinaryTreeNode(); BinaryTreeNode node7 = new BinaryTreeNode(); node1.data = 1; node2.data = 2; node3.data = 3; node4.data = 4; node5.data = 5; node6.data = 6; node7.data = 7; node1.left = node2; node1.right = node3; node2.left = node4; node2.right = node5; node5.left = node7; node3.right = node6; System.out.println("递归求二叉树深度: "+treeDepth(node1)); } }
这道题比较简单,没什么好说的。
题目二:输入一颗二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一颗平衡二叉树。
方法一:需要重复遍历多次的解法,简单但不足以打动面试官
1 public static boolean isBalanced_1(BinaryTreeNode root){ 2 if(root==null){ 3 return true; 4 } 5 int left = treeDepth(root.left); 6 int right = treeDepth(root.right); 7 int diff = left - right; 8 if(diff>1||diff<-1){ 9 return false; 10 } 11 return isBalanced_1(root.left)&&isBalanced_1(root.right); 12 }
该方法简洁,但是一个结点会被重复遍历多次,时间效率不高。
方法二:每个结点只遍历一次,面试官喜欢
1 class Tuple{ 2 private boolean isBalanced; 3 private int depth; 4 5 public Tuple(){} 6 public Tuple(boolean isBalanced, int depth) { 7 super(); 8 this.isBalanced = isBalanced; 9 this.depth = depth; 10 } 11 //-----isBalanced,Getters and Setters---- 12 public boolean getIsBalanced() { 13 return isBalanced; 14 } 15 public void setIsBalanced(boolean isBalanced) { 16 this.isBalanced = isBalanced; 17 } 18 //-----depth,Getters and Setters---- 19 public int getDepth() { 20 return depth; 21 } 22 public void setDepth(int depth) { 23 this.depth = depth; 24 } 25 26 27 } 28 //----判断平衡二叉树,每个结点只遍历一次---- 29 private static Tuple isBalanced(BinaryTreeNode root){ 30 if(root==null){ 31 Tuple tuple = new Tuple(); 32 tuple.setIsBalanced(true); 33 tuple.setDepth(0); 34 return tuple; 35 } 36 Tuple left = isBalanced(root.left); 37 Tuple right = isBalanced(root.right); 38 39 if(left.getIsBalanced()&&right.getIsBalanced()){ 40 int diff = left.getDepth()-right.getDepth(); 41 if(diff<=1&&diff>=-1){ 42 return new Tuple(true,(left.getDepth()>right.getDepth()?left.getDepth():right.getDepth()) + 1 ); 43 } 44 } 45 return new Tuple(false,-1); 46 } 47 public static boolean isBalancedBinaryTree(BinaryTreeNode root){ 48 Tuple tuple = isBalanced(root); 49 return tuple.getIsBalanced(); 50 }
在上面的代码中,我们使用后序遍历的方式遍历整颗二叉树。在遍历某结点的左右子结点之后,我们可以根据它的左右子结点的深度判断它是不是平衡的,并得到当前结点的深度。当遍历到根结点的时候,也就判断了整颗二叉树是不是平衡二叉树。由于要传递两个参数,一般的使用返回值的方法是行不通的,而且Java并不存在指针和简单数据类型的引用传值。一般的高级语言(如Python)会有元组这么一个概念(Java没有那就自己定义一个),既然只能返回一个值,那就返回一个复合类型的,函数改造完成~
我想说的是,每个入了门的程序员都知道参数是复制传值,在C/C++中只能用指针和引用的方式从参数列表中传递或获取值,在Java中,除了基本数据类型和String类型外,也是引用传值。但是基本数据类型传进函数体你改动了有什么意义?你只是改动了一个副本。为了呵护祖国下一代程序员的健康成长,老夫专门抽时间写了一篇博客(抠鼻),打击不良之风~ 本来想和平衡二叉树结合一起写一篇文章,但是平衡二叉树TMD代码一下子要写500多行,我表示受到了惊吓,有机会再说吧