位于树中较低层的结点是上一层的孩子html
同一双亲的两个节点称为兄弟node
没有任何孩子的结点称为叶子git
一个至少含有一个孩子的非根结点称为一个内部结点数组
根是树中全部结点的祖先,沿着某一特定结点的路径可到达的结点是该结点的子孙。函数
结点的层就是从根节点到该结点的路径长度。从根到该结点 的边数目就是其路径长度。
学习
树的高度是指从根到叶子之间最远路径的长度。测试
树中任一结点能够具备的最大孩子数目为该树的度。this
对结点所含有的孩子数目无限制的树称为广义树。lua
每一个节点限制为不超过n个孩子的树称为一棵n元树。.net
节点最多含有两个孩子的树称为二叉树。
树的全部叶子都位于同一层或相差不超过两层,就称该树是平衡的。
若是树是平衡的且底层全部叶子都位于树的左边,则认为该树是彻底的。(即满二叉树去掉最下层右边的若干个结点)。
若是一个n元树的全部叶子都位于同一层且每一结点要么是一片叶子要么正好具备n个孩子,则称该树是满的。(满二叉树是特殊的彻底二叉树)。
具备n个结点的彻底二叉树的高度为(log2n)+1。
表达式树的根及其内部结点包含着操做,且全部叶子也包含着操做数。对表达式树的求值是从下往上的。
Postfix类和PostfixEvaluator类的理解图示更清楚,对于操做数,创建一个新的ExpressionTreeObj,构造一个ExoressionTree压入栈中,遇到操做符,弹出栈顶的两个ExpressionTrees,使用该操做符创建一个新的ExpressionTree压入栈中。而且须要注意的是,该表达式树栈的栈顶位于右边。
Postfix类的UML描述
问题一解决:因为findAgain方法使用了递归,他就须要使用一个私有支持方法,由于第一个调用和随后每一个调用的签名和行为多是不相同的。那就是说,若是没有findAgain方法中的递归部分,那么find方法就只能用来查找根结点,若是要查找内部结点的话,就须要使用递归部分,单纯用find方法须要很复杂的程序实现。
问题二解答:首先上网查找了一下部分代码但愿能找到解释,而后就找到了侯泽洋同窗的博客...里面有一样的问题。而后他给我讲解了一下具体思路。我把个人理解在代码中进行了注释。
public String printTree() { UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>(); UnorderedListADT<Integer> levelList = new ArrayUnorderedList<Integer>(); BinaryTreeNode<ExpressionTreeOp> current; String result = ""; int printDepth = this.getHeight();//树的高度 int possibleNodes = (int) Math.pow(2, printDepth + 1);//因为根节点位置是0,最下层是第printDepth+1层,这个二叉树可能的总结点数就是2的printDepth+1次方 int countNodes = 0;//结点数目 nodes.addToRear(root);//在无序列表中添加根部结点 Integer currentLevel = 0;//当前层 Integer previousLevel = -1;//前一层 levelList.addToRear(currentLevel);//把当前层添加到层数链表中 while (countNodes < possibleNodes) {//此树不满时 countNodes = countNodes + 1;//从0开始加 current = nodes.removeFirst();//把第一个数取出来 currentLevel = levelList.removeFirst();//设置成当前层数 if (currentLevel > previousLevel) {//若是不在同一层就换行 result = result + "\n\n";//进行换行 previousLevel = currentLevel;//层数下移 for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++) result = result + " ";//每一层加空格,第n层有2^(n-1)个数 } else {//若是在同一行,每两个数之间加空格 for (int i = 0; i < (Math.pow(2, (printDepth - currentLevel + 1)) - 1); i++) { result = result + " "; } } if (current != null) {//若是当前结点不为空,记录他的左右孩子,并增长层数 result = result + (current.getElement()).toString(); nodes.addToRear(current.getLeft()); levelList.addToRear(currentLevel + 1); nodes.addToRear(current.getRight()); levelList.addToRear(currentLevel + 1); } else {//若是当前结点为空,给他分配空间,存一个null进去 nodes.addToRear(null); levelList.addToRear(currentLevel + 1); nodes.addToRear(null); levelList.addToRear(currentLevel + 1); result = result + " "; } } return result; }
问题一:实例化LinkedBinaryTree时,若是使用构造函数
public LinkedBinaryTree(T element, LinkedBinaryTree<T> left, LinkedBinaryTree<T> right) { root = new BinaryTreeNode<T>(element); root.setLeft(left.root); root.setRight(right.root); }
当某个参数为空时,如图,就不能运行,产生空指针的错误提示。
问题一解决:我开始的时候认为参数有null能够是一个空位,但运行出现空指针错误,而后把参数改成肯定的数后就不出错了...实际上是一个很低级的错误,参数为空的话就没有指针了,固然不能运行(▼ヘ▼#)
问题二:当树中没有要查找的结点时,因为个人contain方法中使用到了find方法,当找不到时,就抛出异常,程序终止了。
public boolean contains(T targetment) { if(find(targetment) != null) return true; return false; }
如图
问题二解决:首先想到把find方法中的
if (current == null) throw new ElementNotFoundException("LinkedBinaryTree");
改成
if (current == null) return null;
这样正好符合contains方法的需求,可是有一点小问题就是更改了find方法后,若是单纯的使用find方法去查找一个不存在的数,那么获得的是一个null,程序并不会终止,但我感受问题不大,嘿嘿。
问题三解决:首先想到在表达树的代码中有printTree方法,原理应该是如出一辙的,可是不能直接拿来用,由于它在打印表达树时,UnorderedListADT<BinaryTreeNode<ExpressionTreeOp>> nodes = new ArrayUnorderedList<BinaryTreeNode<ExpressionTreeOp>>();
BinaryTreeNode<ExpressionTreeOp> current;
参数均为ExpressionTreeOp,而其中既有操做数又有操做符,而在二叉树的打印中只有数字结点,且有如图冲突
因此只须要把他改成泛型便可打印任意树。
UnorderedListADT<BinaryTreeNode<T>> nodes = new ArrayUnorderedList<BinaryTreeNode<T>>();
BinaryTreeNode<T> current;
问题四:在作哈希表的实验时,链表出现错误
问题四解决:首先在每次插入链表后进行输出,找到了错误的地方
如图可见,当出现冲突的时候,会丢失本来在那个位置的数,因此就是insert方法中处理冲突的代码有错,检查代码后发现
public void insert(LinkHash link) { int data = link.getData(); LinkHash previous = null; LinkHash current = first; while(current!=null&&data>current.getData()) previous = current; current = current.next; count++; alltime++; } if (previous == null) { first = link; alltime++; } else { previous.next = link; link.next = current; //count++; alltime++; } }
while循环的条件while(current!=null&&data>current.getData())
是错误的,有冲突的那个位置造成的链表是按前后顺序排的,并不须要从小到大,因此说当1进去时,他比11小,因此直接执行else操做,就丢失原来的11了。应把条件改成while (current != null)
便可。
没有错题
这周对于树的学习属于拨云见日吧。想起来刚开始学Java的时候,我就在博客中写过,单纯的看书看完后容易一脸懵逼,这时候就选择直接分析代码,如今我又回到了当时的状态,刚看完书的时候怎么也理解不了一些方法,后来直接作pp,尝试摸索一下就理解不少知识点。哎,Java这东西不能太较真,随他去吧。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | |
---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 |
第一周 | 0/0 | 1/1 | 8/8 |
第二周 | 1163/1163 | 1/2 | 15/23 |
第三周 | 774/1937 | 1/3 | 12/50 |
第四周 | 3596/5569 | 2/5 | 12/62 |
第五周 | 3329/8898 | 2/7 | 12/74 |
第六周 | 4541/13439 | 3/10 | 12/86 |