zoukankan      html  css  js  c++  java
  • 20172305 2018-2019-1 《Java软件结构与数据结构》第六周学习总结

    20172305 2018-2019-1 《Java软件结构与数据结构》第六周学习总结

    教材学习内容总结

    本周内容主要为书第十章内容:

    • 树(一种非线性结构,其中的元素被组织成一个层次结构)

      • 结点:树中的一个位置。
      • :树中两个结点的连接。
      • 根结点:就是指位于该树顶层的唯一结点。一棵树只有一个根结点,根结点没有父节点。
      • 子结点:一个树中较低层的结点是上一层结点的子结点。位于树中当前结点下面的结点,并由边与之直接连接。
      • 同胞结点:属于同一结点的子结点。
      • 叶结点:没有任何子结点的结点。
      • 内部节点:一个至少有一个子结点的非根节点。
      • 祖先节点:位于当前结点以上的结点。
      • 后代结点:位于当前结点一下的结点。
      • 路径长度:通过计算从根到该结点所必须越过的边数目。
      • 高度:从根到叶子之间的最远路径的长度。
      • 阶(度):树中任一结点可以具有的最大子结点的数目。
    • 树的分类:

      • 二叉树:结点最多具有两个孩子的树。
      • 完全树:如果某树是平衡的,且底层所有叶子都位于树的左边,则认为该树是完全的。
      • 满树:如果一颗n元树的所有叶子都位于同一层且每一结点要么是一片叶子,要么是正好具有n个孩子。
      • 完全二叉树:在每个K层上都有2^k个结点,最后一层除外,在最后一层中的结点必须是在最左边结点。/ 在每个k层上都具有2^k个结点,最后一层除外,在最后一层中的结点必须是最左的。
      • 平衡树与非平衡树
    • 含有m个元素的平衡n元树具有的高度为lognm。

    • 树的遍历:

      • 前序遍历:从根结点开始,访问每一个结点及其孩子。(A->B->D->E->C)
      • 中序遍历:从根结点开始,访问结点的左侧孩子,然后是该结点,再然后是任何剩余的结点。(D->B->E->A->C)
      • 后序遍历:从根结点开始,访问结点的孩子,然后是该结点。(D->E->B->C->A)
      • 层序遍历:从根节点开始,访问每一层的所有结点,一次一层。(A->B->C->D->E)
    • 对于任何存储在数组位置n处的元素而言,该元素的左结点将存储在位置2n+1处,该元素的右结点将存储在位置2(n+1)处。

    • 模拟链接策略允许连续分配数组位置而不用考虑该树的完全性。

    • 二叉树--表达式树表达式树的及其内部结点包含着操作,且所有叶子也包含着操作数。对操作树的求值是从下往上的。

    • 二叉树--决策树(背部疼痛诊断器)决策树的结点表示决策点,其子结点表示在该决策点的可选项。决策树的叶结点表示可能的判断,这些推断是根据决策结果得出的。

    教材学习中的问题和解决过程

    • 问题1:完全二叉树和满二叉树的区别?
    • 问题1解决方案:满二叉树是完全二叉树的一种特殊。故满二叉树肯定是完全二叉树,完全二叉树不一定是满二叉树。是因为完全二叉树倒数第二层的结点可以有一个子结点(当然是左侧节点),可以有两个结点,也可以无子结点。而满二叉树则要最后一层的结点数必须为最大的,这就要求倒数第二层的每个结点其子结点必须是两个 即为满二叉树的倒数第二层的结点无叶结点的情况。
    • 满二叉树是指除最后一层外,每一层上的所有结点都有两个子结点。
      • 如果一颗满二叉树的深度为d,最大层数为k
      • 它的叶子数是: 2^d
      • 第k层的节点数是: 2^(k-1)
      • 总节点数是: 2^k-1 => (1 + 2 + 4 + 8 ··· + 2^(k-1)的和),其总节点数一定是奇数。
    • 完全二叉树是指除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。
    • 完全二叉树的判断方法:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
    • 完全二叉树的特点是:
      • 只允许最后一层有空缺结点且空缺在右边,即叶子结点只能在层次最大的两层上出现。
      • 对任一结点,如果其右子树的深度为j,则其左子树的深度必为j或j+1。 即度为1的点只有1个或0个。
    • 问题2:书上表达式树printTree()代码如何理解?
    • 问题2解决方案:PostfixEvaluator类的getTree()内容是(treeStack.peek()).printTree()是把树的形式从栈treeStack的顶部返回出来,再调用Expreesion类中的printTree方法(最恶心的部分),就成一棵树了。
    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);
    		int countNodes = 0;
    
    		nodes.addToRear(root);
    		Integer currentLevel = 0;
    		Integer previousLevel = -1;
    		levelList.addToRear(currentLevel);
    
    		while (countNodes < possibleNodes) {
    			countNodes = countNodes + 1;
    			current = nodes.removeFirst();
    			currentLevel = levelList.removeFirst();
    			if (currentLevel > previousLevel) {
    				result = result + "
    
    ";
    				previousLevel = currentLevel;
    				for (int j = 0; j < ((Math.pow(2, (printDepth - currentLevel))) - 1); j++)
    					result = result + " ";
    			} 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 {
    				nodes.addToRear(null);
    				levelList.addToRear(currentLevel + 1);
    				nodes.addToRear(null);
    				levelList.addToRear(currentLevel + 1);
    				result = result + " ";
    			}
    
    		}
    		return result;
    	}
    
    • 代码中的两个无序列表,一个存放的是BinaryTreeNode类型,就是表达式树的每一个结点;另一个存放的是Integer类型,用来与之前的无序列表对应,每往无序列表中存放一个结点,就在另一个无序列表中存入对应的层数。

    • 代码中的几个整形变量,printDepth输出的是高度(从零开始的,实际树是四层就输出三层,根结点所在层数为0),possibleNode通过调用Math的静态方法pow()来算树的最大结点数。其中Math.pow(2, printDepth + 1)按照老师讲的应该是2^printDepth - 1,但是算法给出的是2^(printDepth+1),实际上我们调用的getHeight()方法会从第零行开始计算,而在实际上是从一层开始的,这样的话就需要把再加1。而尾部的减1,没有再此体现。在后面的while循环的条件来看,记录输出结点数量的变量 < possibleNodes,这样的话就可以使得记录输出结点数量的变量最大情况等于possibleNodes - 1,这样就是最大结点数。还有三个整形变量,一个是countNodes,是记录输出的结点数目的;一个是currentLevel记录当前结点所在的层;一个是previousLevel记录的是当前结点的前一层。

    • 过程:调出根结点A,此时对应的层数是-1,存放到对应的无序列表中。此时,countNodes(输出的结点数目)的初始值为0,
      开始第一次进入循环,countNodes加1,调出无序列表中的结点。此时根结点的层数为0,前一层为-1,进入第一个条件,换行previousLevel等于currentLevel(两个变量值都为0),然后输出根节点的内容,跳出第一个条件。进入第二个条件,将根结点的左子结点添加到无序列表的尾部,对应的记录层数的无序列表添加数字1,再将根结点的右子结点添加到无序列表,对应记录层数的无序列表添加数字1,第一次循环结束。
      进行第二次循环,此时调出根结点的左子结点的内容和左子结点的层数,层数为1,前一层是0,进入第一个条件,换行previousLevel等于currentLevel(两个变量值都为1),然后输出左子结点的内容,跳出第一个条件。进入第二个条件,往里面插入左结点的子结点,此时存放节点的无序列表内有和输出的左结点同一层的右结点,和左结点的两个子结点,先左节点后右结点,对应的层数应该均为3,第二次循环结束。
      进行第三次循环,此时调出的是根结点的右子结点和层数,层数和左结点相同也为1,进入第一个条件(else部分),取消了换行和previousLevel等于currentLevel,这样的话就和左子结点同行输出,把根结点的两个子结点都输出来了。跳出第一个条件,再将右结点的两个子结点和对应的层数放到无序列表,其中两个子结点的层数均为2,第三次循环结束。
      进行第四次循环,此时调出的根结点的左结点的左子结点,此时对应的层数是2。此时的previousLevel为1,currentLevel为2,进入第一个条件的if部分,进行换行并输出该结点的内容,跳出第一个条件,因为该结点为空,所以进入第二个条件的else部分,会默认添加该结点的两个子结点,但是子结点的内容为空,即插入到无序列表的内容为空,但是层数会进行增加,第四次循环结束。
      重复进行上述循环(已经调用整个部分的相关代码,股不在叙述操作),最后达到循环超过该树的总结点数即possibleNodes跳出循环,输出result就是整个树了。

    • 问题3:背部疼痛诊断器的诊断过程总是回答完一个yes之后就蹦了?

    • 问题3的解决方案:针对这个问题,刚开始只是敲上去而没有真正去运行。后来听同学的运行之后有问题,这才去运行,结果真有问题。不能转化为String,很神奇!!!明明在txt文件内已经有了内容的,就是转换不成String。刚开始以为是读文件的部分有问题,但是没找到问题,通过单步调试也只是在最后一步有问题。所以,很疑惑!更关键的是这个同样的代码在别的电脑上会有运行成功的。相同的一段代码,我的电脑上会提醒有个判断总是false,而别的上面就没有。很迷...通过侯泽洋的帮助,是我们在获得左结点或是右结点时候只是调出其中的内容,该节点的子结点根本没有调出来导致的,完全就是个只有该结点的一个树了,在LinkedBinaryTree中添加几句就可以结点的子结点都调出来了。

      • 始终有问题的部分:

      • 错误图片:
      • 王文彬提供的代码(修改位置):

      • 侯泽洋提供的代码(修改位置):

    代码学习中的问题和解决过程

    • 问题1:链表实现的二叉树的toSring代码如何编写?

    • 问题1的解决方案:return super.toString();会出现带有包名的哈希码,没有正常的输出内容。准备重新书写的输出的代码的时候,发现如果输出的话就需要用递归的方法,来从树中一层一层的从左往右的按顺序输出。但是如果用到了递归的话,注定用String类型的变量输出不出来(因为要进行一个叠加的过程,而设置变量的话也不能在此方法下进行输出。需要像之前的那个归并排序和快速排序一样,一个进行递归的主要方法,另一个调用该递归方法,来达到代码的实现。)图过时用递归来实现的话,就可以运用不同的遍历方式。通过书上代码--表达式树的输出树状形式,就直接搬过来实现toString方法(相关代码分析在教材分析总结)。

      • 产生带包名哈希码:
      • 前序输出:从根结点开始,访问每一个结点及其子结点。所以,先调出根结点的内容,然后从左结点开始调出至右结点的内容。
      • 中序输出:从根结点开始,先访问结点的左子结点的内容,在调出该结点的内容,再访问结点的右子结点的内容。
      • 后序输出:从根结点开始,先访问该结点的子结点的内容,在退回到结点的内容。
      • 层序输出:从根节点开始,每一层的从左到右的进行输出。

      • 树状输出(借鉴表达式树的形式):

    • 问题2:表达式树的输出为什么总是输出不对?

    • 问题2解决方案:书上表达式树的代码在进行树的输出时候,总会输出的稀乱稀乱的一堆,代码也没有爆红。第一次通过单步调试发现,是自己的getHeight()方法的方法体没有写,导致输出的结果总是0。还要自己修改getHeight()...悲惨自行补了相关代码,先判断树是不是空的,不空的话通过PP10.3做的代码,进行判断是否是叶结点进行循环遍历,在遍历的过程中进行计数。但是在输出树的情况下就是缺最后一行,通过尝试对一个已知高度的树调用getHeight()方法时,在输出的时候发现会比实际高度少1,所以在计数变量的初始值从0改为1尝试一下,结果就完整了。

      • 第一次修改:
      • 第二次修改:
      • 第三次修改:
    • 问题3:removeRightSubtree、removeAllElement和contains方法

    • 问题3解决方案:

      • 针对removeRightSubtree方法觉得需要先进行遍历,每遍历一个再删除一个,直到完成任务。后来想想觉得好麻烦,还要进行迭代。想出一个简单粗暴的方法,就是已经确定删除右枝杈了,那么就直接把节点的右侧枝杈直接改为null就可以了,根本不用管其内容就是删。但是,做出的第一个版本,是删除根结点的右侧,那么如果想删除某个节点的右侧,这样的话方法就不会起作用。所以,改进了此方法以实现可以删除某一个节点的右子结点。
      • 针对removeAllElement方法,因为实现前一个方法时简单粗暴,而此方法和之前的有一定的类似,所以直接就重新定义一个BinaryTreeNode类的根结点,让其为零,再使这个结点替代之前有内容的树就可以了。
      • 针对contains方法,这个方法是判断指定目标是否在该树上。因为之前有书上的find方法作支撑,就通过该方法查找出是否有指定元素,如果就输出true,没有就false。

    代码托管

    上周考试错题总结

    无错题,终于不用错题总结了...

    结对与互评

    点评(王禹涵)

    • 博客中值得学习的或问题:
      • 背景图很好看,但是截图内容看得不是很清晰。问题2的代码也进行了注释,是我应该学习的地方。
    • 代码中值得学习的或问题:
      • 代码图片也是看的不清晰,问题提的很好,问题2出现的是哈希码,建议可以尝试这用四种遍历顺序输出,或是像树那样输出。
    • 基于评分标准,我给本博客打分:8分。
      • 得分情况如下:
      • 正确使用Markdown语法(加1分)
      • 模板中的要素齐全(加1分)
      • 教材学习中的问题和解决过程, 两个问题加2分
      • 代码调试中的问题和解决过程, 两个问题加2分
      • 感想,体会不假大空的加1分
      • 点评认真,能指出博客和代码中的问题的加1分

    点评(方艺雯)

    • 博客中值得学习的或问题:
      • 图片特别细致清晰,而且针对实现树的策略写的很详细,针对printTree方法可以更进一步的描述运算过程。
    • 代码中值得学习的或问题:
      • 代码问题记录详细,第二个问题我也遇到过。建议在插图的时候可以添加多一点的文字描述,没有什么大问题,写的很棒棒。
    • 基于评分标准,我给本博客打分:10分。
    • 得分情况如下:
      • 正确使用Markdown语法(加1分)
      • 模板中的要素齐全(加1分)
      • 教材学习中的问题和解决过程, 二个问题加2分
      • 代码调试中的问题和解决过程, 四个问题加4分
      • 感想,体会不假大空的加1分
      • 点评认真,能指出博客和代码中的问题的加1分

    互评对象

    感悟

    第十章的树学起来很费劲,完全的一个接着一个,没有顺序,没有结构的(二叉树还好点)。课后的代码相对简单,但是书上的示例代码写的比课后代码还麻烦。非常感谢侯泽洋的帮助,帮助我更好的理解树的相关知识,有些代码的问题是在帮助下完成的,这也显示出我的不足,没有更好的掌握知识,逻辑的相关内容只有自己弄懂才行,别人的帮助只是辅助的。起初还感觉前面代码相对简单,但那是到了树的部分真是欲哭无泪的感觉。只能再好好的学习学习再学习了。

    学习进度条

    代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
    目标 5000行 30篇 400小时
    第一周 0/0 1/1 15/15
    第二周 703/703 1/2 20/35
    第三周 762/1465 1/3 20/55
    第四周 2073/3538 1/4 40/95
    第五周 981/4519 2/6 40/135
    第六周 1088/5607 2/8 50/185

    参考资料

  • 相关阅读:
    Leetcode Binary Tree Preorder Traversal
    Leetcode Minimum Depth of Binary Tree
    Leetcode 148. Sort List
    Leetcode 61. Rotate List
    Leetcode 86. Partition List
    Leetcode 21. Merge Two Sorted Lists
    Leetcode 143. Reorder List
    J2EE项目应用开发过程中的易错点
    JNDI初认识
    奔腾的代码
  • 原文地址:https://www.cnblogs.com/sanjinge/p/9853110.html
Copyright © 2011-2022 走看看