20172328 2018-2019《Java软件结构与数据结构》第八周学习总结

20172328 2018-2019《Java软件结构与数据结构》第八周学习总结

概述 Generalization

本周学习了二叉树的另一种有序扩展?是什么呢?你猜对了!ヾ(?°?°?)??就是堆。本章将讲解堆的链表实现and数组实现,以及往堆中添加元素或从堆中删除元素的算法;还将介绍对的一些用途,包括基本使用和优先队列。

教材学习内容总结 A summary of textbook

  • (heap)就是具有两个附加属性的一颗二叉树:

    • 第一点:它是一颗完全二叉树 ,即叶子节点都在最后一层靠左侧。
    • 第二点:对每一结点,它小于(大于)或等于其左孩子和右孩子。
  • 第二点中满足大于的条件下形成的是一个最大堆(大顶堆),反之则为最小堆(小顶堆)。
  • 最小堆将其最小元素存储在该二叉树的根处,且其跟的两个孩子同样还是最小堆。
  • 堆中的操作:
  • addElement操作
    • addElement方法将给定的Comparable元素添加到堆的恰当位置处,且维持该堆的完全性属性和有序属性。

      • Little Tip:完全树你还记得吗?完全二叉树就是所有叶子都位于h或者h-1层,其中h为log2(n),且n为树中的元素数目,h层的所有叶子都位于该树的左边,那么该树被认为是完全的。
    • 堆就是一棵完全的二叉树,所以对于插入的新结点只存在一个正确的位置。要么是h层左边的下一个空位置,要么是h+1层左边的第一个位置(如果h层为满的话)。
    • 将新结点定位到正确的位置后,我们就必须对这个堆进行排序来保持其有序属性。方法就是对树中的最末一片叶子进行跟踪记录,在一个addElement方法后,最末结点就被设定为插入结点。也就是通过上溯树来保证树的有序性.
  • removeMin操作
    • removeMin方法将删除最小堆中的最小元素并返回它,由于最小元素是存储在最小堆的根处,所以我们需要返回储存在根处的元素并用堆中的另一元素替换它。
    • 要维持该树的完全性,就是把储存在树中最末一片叶子上的元素用来替换根元素。
    • 将存储在最末一片叶子上的元素移动到根处,就必须对该堆进行重新排序来维持该堆的排序属性。
    • 要维持该堆的排序属性,就要从根结点下溯树。具体过程是将该新根元素与其较小的孩子进行比较,且如果孩子更小就将它们互换,沿着树向下继续这一过程,直至该元素要么位于某一叶子中,要么比它的两个孩子都小。
  • findMin操作
    • findMin将返回一个指向最小堆中最小元素的引用,由于最小堆的最小元素就在根处,所以直接返回存储在根处的元素即可。
  • 使用堆——堆排序heapSort
    • 堆排序是对简单选择排序的一种改进。
    • 改进着眼点:如何减少关键字的比较次数
      • 简单选择排序在一趟排序中仅选出最小关键字,但是没有把一趟比较结果保存下来,因而比较次数较多。
      • 堆排序在选出最小关键字同时,也找出较小的关键字,从而减少了后面选择中的比较次数,提高了整个排序效率。
  • 左右子树都是大顶堆,如何调整根结点,使得整棵树成为一个堆?
  • 堆调整 —— 筛选过程
    • 调整过程中,总是将根结点(被调整结点)与左右孩子比较;
    • 不满足堆条件时,将根结点与左右孩子中较大者交换;
    • 这个调整过程一直进行到所有子树都是堆或者交换到叶子为止。
    • 这个从堆顶到叶子的调整过程称为“筛选”。
  • 对堆进行筛选完毕之后我们就要为保持其有序性而开始排序。
  • 堆排序-排序过程


    • 从无序序列的第[n/2]个元素开始(对应于完全二叉树的最后一个非终端结点)进行筛选;
    • 当解决一个非终端结点(非叶子结点)的有序问题后,把此非终端结点看做一个叶子,然后继续上溯,找到倒数第二个非终端结点,继续进行有序替换,知道整个堆有序为止。
  • heapSort的复杂度为O(nlogn)
  • 使用堆:优先级队列
  • 优先级队列(Priority queue)就是遵循两个排序规则的集合。
    • 首先,具有更高优先级的项目在先。
    • 其次,具有相同优先级的项目使用先进先出方法来确定其排序。
      • Little Tip:虽然最小堆根本就不是一个队列,但是它却提供了一个高效的优先级队列实现。
  • 用链表实现堆
    • 因为我们要求在插入元素后能够向上遍历该树,所以堆中的结点必须存储在指向其双亲的指针。所以我们从创建一个HeapNode类开始我们的链表实现,该类对BinaryTreeNode进行了拓展并添加了一个双亲指针。
    • 链表实现的实例数据由指向HeapNode且称为lastNode的单个引用组成,这样我们就能够跟踪记录该堆中最末一片叶子。public HeapNode lastNode;
    • addElement操作:
      • 在恰当的位置添加一个新元素
      • 对堆进行重排序以维持其排序属性
      • 将lastNode指针重新设定指向新的最末结点
    • removeMin操作:
      • 用存储在最末结点处的元素替换存储在根处的元素
      • 对堆进行重排序
      • 返回原始的根元素
    • findMin操作:
      • 该方法仅仅返回一个指向存储在堆根处元素的引用,因此复杂度为O(1)。
  • 用数组实现堆
    • 用数组实现堆不再需要创建一个HeapNode类对,而是通过用数组来保存堆中的数据。
    • 在二叉树的数组实现中,树的根位于位置0处,对于每一结点n,n的左孩子将位于数组的2n+1处,右孩子将位于数组的2n+2处。
    • addElement操作:
      • 在恰当的位置添加一个新元素
      • 对堆进行重排序以维持其排序属性
      • 将count递增1.
    • removeMin操作:
      • 用存储在最末结点处的元素替换存储在根处的元素
      • 对堆进行重排序
      • 返回原始的根元素
    • findMin操作:
      • 返回指向存储在堆的根处或数组0位置处的元素。
  • 总结:链表实现和数组实现的addElement方法和removeElement方法时间复杂度都是O(logn)。但是,数组的实现还是更高效一些,因为在addElement操作中数组实现不用去确定插入双亲的结点,在removeElement操作中数组实现不需要确定新的最末一片叶子。

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

  • 问题1:周四晚上看用链表实现堆的添加操作代码。刚刚看懂小伙伴仇夏来找我讨论,讨论了一会瞬间觉得自己没有真正看懂,那段奇妙的代码如下:
private HeapNode<T> getNextParentAdd()
    {
        HeapNode<T> result = lastNode;

        while ((result != root) && (result.getParent().getLeft() != result))
            result = result.getParent();

        if (result != root)
            if (result.getParent().getRight() == null)
                result = result.getParent();
            else
            {
                result = (HeapNode<T>)result.getParent().getRight();
                while (result.getLeft() != null)
                    result = (HeapNode<T>)result.getLeft();
            }
        else
            while (result.getLeft() != null)
                result = (HeapNode<T>)result.getLeft();

        return result;
    }

这段代码是返回将要插入结点的双亲结点的方法,当时我和仇夏讨论的是有两种情况。因为我们知道插入操作为了保证树的完全性,所以要在h层的从左开始数的第一个空结点插入或者在h+1层的最左边插入(如果树是满的话),但是在循环体中不满足我们的要求。

  • 问题1的解决:
  • 问题的重点是“下一个将要插入结点的双亲结点”,之前一直理解的是新插入结点的双亲结点,所以当然不对。在理解正确之后,画出几种插入的可能情况,再跟着上述代码理解几遍,就慢慢清晰明朗了。
  • 问题2:之前在学习栈的时候感觉一直在和堆一起被提起,所以堆和栈之间到底是什么关系?
  • 问题2的解决:
  • 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存。
  • 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
  • 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
  • 堆和栈的区别比较:
    • 1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
    • 2.栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
    • 3.Java中的数据类型有两种。 一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

代码实现时的问题作答 Exercise

  • 问题1:用堆实现队列?树中给的堆是由数组和链表实现的,那么我们应该用ArrayHeap还是Linkedheap实现呢?又该如何实现?
  • 问题1的解决:首先,我们知道在第十章中队列的实现可以由链表或者循环数组实现,并且堆可以由链表和数组实现,因此是否可以推出队列可以由数组实现的堆或者链表实现的堆来实现呢?
  • 首先,我先用链表实现的堆来实现队列。通过在enqueue方法中调用addElement方法,就能够实现队列的入队,但是在入队后进行了堆的插入中的排序?队列是符合先进先出原则的,那么我就修改了堆中的插入方法,将其中的排序删掉。同理,当出队时也不应该去考虑排序的问题。但是当我删除掉删除的排序后,再执行删除队列中前两个元素,我却发现删除的并不一定是队列的前两个值,反而删除掉了最开始跟的值和最末一个叶子,这是由堆的性质决定的。所以想要保持先进先出,我们就要找到堆顶的左孩子然后删除。所以我们需要改变一下堆中的排序方法。链表的实现方法很麻烦,而且要改变删除的排序算法需要考虑很多种情况,在做了两小时还是不能完整正确的情况下,让我们把目光投向数组。
  • 数组中只需要将删除后的最末结点变成null就可以达到效果。

上周测试活动错题改正 Correction

  • 1.In removing an element from a binary search tree, another node must be ___________ to replace the node being removed.
    A .duplicated
    B .demoted
    C .promoted
    D .None of the above
  • 正确答案选 B。当在二叉查找树上删除一个结点时,后面的结点需要向上移动来补全。当时,以为越靠近根结点说明深度越低,所以是降级了;但是看完答案好像人家的意思是向上补全。题意理解不准确哈哈
  • 2.In removing an element from a binary search tree, another node must be demoted to replace the node being removed.
    A .True
    B .Flase
  • 正确答案选 A ,和第一题一模一样好吗?哭
  • 3.One of the uses of trees is to provide simpler implementations of other collections.
    A .True
    B .Flase
  • 正确答案选 B 。这道题确实是我自己不太懂的。通过搜索得知,java中树的应用主要有:菜单树,还有权限树,商品分类列表也是树结构。在这几章的学习中,好像确实没有通过树来简单实现其他集合,树提供的方便性可以用于查找、排序等等。
  • 4.Insertion sort is an algorithm that sorts a list of values by repetitively putting a particular value into its final, sorted, position.
    A .true
    B .false
  • 正确答案选 B ,我当时选了A。我觉得还是题意理解的问题。我理解的题意是“插入排序是一种重复的将特殊值插入后面,然后排序,然后安置的算法”我觉得插入排序就是这样一个流程,所以我也不知道出现了什么问题。

码云链接

代码量(截图)

结对及互评Group Estimate

  • 点击进入结对小伙伴20172301郭恺的博客
  • 点击进入结对小伙伴20172304段志轩的博客

点评模板:

  • 博客中值得学习的或问题:

    • 20172301:
    • 20172304:

其他(感悟、思考等,可选)Else

Crossing miles of frustrations and rivers a raging,picking up stones I found along the way.

怕不轻松,怕太轻松。
再也不用觉得工作日长,因为每天好像都是工作日。想忙里偷闲就忙里偷闲,想抓紧做事就抓紧做事。

我将每天告诉自己:请对专业课程更加虔诚一点。

学习进度条Learning List

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积)
目标 5000行 30篇 400小时
第一周 0/0 1/1 8/8
第二周 621/621 1/2 12/20
第三周 678/1299 1/3 10/30
第四周 2734/4033 1/4 20/50
第五周 1100/5133 1/5 20/70
第六周 1574/6707 2/7 15/85
第七周 1803/8510 1/8 20/105
第八周 2855/11365 2/10 25/130

参考资料Reference

原文地址:https://www.cnblogs.com/LXY462283007/p/9939573.html

时间: 2024-08-29 01:40:54

20172328 2018-2019《Java软件结构与数据结构》第八周学习总结的相关文章

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

20172305 2018-2019-1 <Java软件结构与数据结构>第一周学习总结 教材学习内容总结 本周内容主要为书第一章和第二章的内容: 第一章 软件质量: 正确性(软件达到特定需求的程度) 可靠性(软件发生故障的频率和危害程度) 健壮性(很好处理错误情况的情况) 可用性(用户在软件中掌握和运行任务的容易程度) 可维护性(软件进行修改的容易程度) 可重用性(软件组件可被其他软件系统开发使用的容易程度) 可移植性(软件组成可用于多种计算机环境中的容易程度) 运行效率(不浪费资源的情况下软

2018-2019-20172321 《Java软件结构与数据结构》第九周学习总结

2018-2019-20172321 <Java软件结构与数据结构>第九周学习总结 教材学习内容总结 第15章 图 无向图 图由顶点和边组成. 顶点由名字或标号来表示,如:A.B.C.D: 边由连接的顶点对来表示,如:(A,B),(C,D),表示两顶点之间有一条边. 无向图:与树类似,图也由结点和这些结点之间的连接构成.这些结点是顶点,而结点之间的链接是边.无向图是一种边为无序结点对的图.于是,记做(A,B)的边就意味着A与B之间有一条从两个方向都可以游历的连接.边记作(A,B)和记作(B,A

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

20172328 2018-2019<Java软件结构与数据结构>第六周学习总结 概述 Generalization 本周学习了第十章:非线性集合与数据结构--树.主要讨论了树的使用和实现,以及考察实现和使用树的实例. 教材学习内容总结 A summary of textbook 树(tree):树是一种非线性结构,其元素被组织成了一个层次结构.下面是树的术语,了解一下吧! 树有一个包含结点(node)和边(edge)的集构成,其中的元素被储存在这些结点中,边则将一个结点和另一个结点连接起来.

20172328 2018-2019《Java软件结构与数据结构》第七周学习总结

20172328 2018-2019<Java软件结构与数据结构>第七周学习总结 概述 Generalization 本周学习了第11章:二叉查找树.在本章中,主要探讨了二叉查找树的概念和各种二叉查找树实现,考察为二叉查找树添加和删除元素的算法以及维护平衡二叉查找树的算法 教材学习内容总结 A summary of textbook 二叉查找树(binary search tree):二叉树定义的扩展,一种带有附加属性的二叉树.附加属性是什么?树中的每个节点,其左孩子都要小于其父节点,而父节点

杨玲 201771010133《面向对象程序设计(java)》第十八周学习总结

 <面向对象程序设计(java)>第十八周学习总结 第一部分:理论知识学习部分 第二部分:实验部分 实验名称:实验十八  总复习 1.实验目的与要求 (1) 综合掌握java基本程序结构: (2) 综合掌握java面向对象程序设计特点: (3) 综合掌握java GUI 程序设计结构: (4) 综合掌握java多线程编程模型: (5) 综合编程练习. 2.实验内容和步骤 任务1:填写课程课后调查问卷,网址:https://www.wjx.cn/jq/33108969.aspx. 任务2:综合编

20172306 2018-2019 《Java程序设计与数据结构》第一周学习总结

20172306 2018-2019 <Java程序设计与数据结构(下)>第一周学习总结 教材学习内容总结 第一章 概述 (程序=数据结构+算法 软件=程序+软件工程) 1.1 软件质量 软件工程师一门关于高质量软件开发的技术和理论的学科 软件工程的目标:1.解决正确性问题 2.按时且在预算之内给出解决方案 3.给出高质量的解决方案 4.以合情合理的方式完成上面的事情 高质量软件的特征 正确性:我认为是我们所做的都是为了解决一个正确性问题. 可靠性:降低软件的故障程度和概率 健壮性:可以很好地

20172306《Java程序设计与数据结构》第九周学习总结

20172306<Java程序设计>第九周学习总结 教材学习内容总结 第十一章: try-catch语句.其中还有finally语句.try是进行某些操作,catch是捕获异常,并通过某些异常来进行某些操作.finally是无论是否有异常都会进行的语句.可以没有catch语句. 异常的传递.我觉得传递,主要是某地方的异常是由其他的方法引起的,异常就会传递到那个方法上.书中的例子可以很好的表现出来. IO异常.书中的内容主要是围绕异常来写.老师在蓝墨云中有写有关IO更为详细的内容.例如创建文件,

201671010118 2016-2017-2《Java程序设计》 第十八周学习心得

已经是第十八周的java学习了,马上面临期末考试了,立马又要进行紧张的复习状态了,感觉也没有做好准备,打算在这周认真复习,好好备战期末考试,在这学期的java学习中,遇到了很多困难也解决了很多,重点的四五六章节内容感觉会有点遗忘,第十章十二章内容的掌握还可以,Swing用户界面组件掌握的不怎么好,在私下我想用更多的时间去努力学习这章内容,复习以前的内容. 这是最后一次的总结,一学期时间很快过去了,感谢代老师以及学长学姐的帮助,学习上一直在认真帮助我们,每周的作用业会认真的给我们批阅,特别感谢老师

20172302 《Java软件结构与数据结构》第四周学习总结

2018年学习总结博客总目录:第一周 第二周 第三周 第四周 教材学习内容总结 第六章 列表 1.列表是对象的有序集合,在 List 界面中定义. List 接口表示集合框架中的列表.列表可以具有重复的元素.并且我们可以在列表中存储多个空值. 2.列表集合 是一种概念性的表示方法,其思想是使事物以线性列表的方式进行组织,就像栈和队列一样,列表也可以使用数组和链表来实现.列表集合没有内在的容量大小,它可以随着需要而增大.列表集合更一般化,可以在列表的中间和末端添加和删除元素. 3.列表可以分为有序