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

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

教材学习内容总结

    • 堆是具备两个附加属性的一棵二叉树
      • 它是一个彻底树
      • 对每一结点,它小于或等于其左孩子和右孩子(这个描述的是最小堆)
      • 一个堆也能够是最大堆,其中的结点大于或等于它的左右孩子
      • 它继承了二叉树的全部操做
    • addElement操做
      • 若是给定元素不是Comparable的,则该方法将抛出一个ClassCastException异常
      • addElement方法将给定的Comparable元素添加到堆中的恰当位置处,且维持该堆的彻底性属性和有序属性。
      • 由于一个堆就是一棵彻底树,因此对于插入的新结点而言,只存在一个正确的位置,要么就是叶子不在一层,那么就取最后一层的空处;要么就是在同一层,就在它的左面的第一个位置。在插入后,就会对它的完整性和有序性进行改变,因此就要进行从新的排序,拿该值和双亲结点进行比较,而后进行互换,而后沿着树向上继续找,直到到正确的位置。
      • 一般,在堆实现中,咱们会对树中的最末一个结点,或更为准确的是,最末一片叶子进行跟踪记录。
    • 例以下面的过程(咱们要插入的是0,由于插入后,不是最小堆,不符合规定,因此咱们进行重排序):

  • removeMin操做
    • 对于最小堆来讲,Min就是根的位置的元素。因此咱们在这个方法上就是将根元素删掉,而后再进行其余操做。
    • 对于这个堆来讲,完整性和平衡性是很重要的,因此为了维持该树的彻底性,只有一个能替换根的合法元素,且它是存储在树中最末一片叶子上的元素。对于最末一片叶子来讲,就是在树最后一层最右边的叶子。
    • 对于addElement来讲,咱们在添加的时候,有可能违背最小堆的特性,一样,对于removeMin来讲,也会出现这样的问题,因此咱们要进行重排序以维持其原有的属性。过程主要是将替换后的元素和它的孩子进行比较,而后依次向下,直到最后的一层,造成最小堆截止。
    • 例以下面的过程:

  • findMin操做
    • findMin就很好理解了,由于Min就是最根部的元素,因此就将返回为root就能够了。
  • 使用堆:优先级队列
    • 优先级队列(priority queue):就是遵循两个排序规则的集合,首先,具备更高优先级的项目优先;其次,具备相同优先级的项目使用先进先出方法来肯定其排序。
    • 虽然最小堆根本不是一个队列,可是它却提供了一个高效的优先级队列实现。
    • 咱们利用堆来实现一个优先级队列:咱们要实现以上的两个排序规则
      • 首先,咱们使用一个最小堆,须要将高优先级的项目在先
      • 其次,咱们要解决的是对相同优先级的进行先进先出的排序
        • 1.建立一个PriorityQueueNode对象,存储将被放置在队列中的元素,该元素的优先级,以及元素放进队列的顺序
        public PrioritizedObject(T element, int priority)
          {
        this.element = element;//元素
        this.priority = priority;//优先级
        arrivalOrder = nextOrder;//放入队列的顺序
        nextOrder++;
          }
        • 2.为PriorityQueueNode类定义一个CompareTo方法,来完成优先级相同时的比较
        public int compareTo(PrioritizedObject obj)
          {
        int result;
        
        if (priority > obj.getPriority())
            result = 1;
        else if (priority < obj.getPriority())
            result = -1;
        else if (arrivalOrder > obj.getArrivalOrder())
            result = 1;
        else
            result = -1;
        
        return result;
          }
  • 链表实现和数组实现的addElement操做的时间复杂度同为o(logn)
  • 链表实现和数组实现的removeMin操做的复杂度同为o(logn)html

  • 用链表实现堆
    • 堆是二叉树的一种扩展,因此在插入元素后仍旧可以向上遍历该树,因此堆中的结点必须存储指向其双亲的指针。
    • 链表实现的实例数据由指向HeapNode且称为lastNode的单个引用组成,这样咱们就可以跟踪记录该堆中的最末一片叶子
    public HeapNode lastNode;
    • addElement操做
      • 达到3个目的:在恰当位置处添加一个新的元素;对堆进行重排序以维持排序属性;将lastNode指针从新设定为指向新的最末结点
      • 其使用了两个私有方法
        • getNextParentAdd:它返回一个指向某结点的引用,该结点为插入结点的双亲
        • heapifyAdd:完成对堆的任何重排序,从那片新叶子开始向上处理至根处
      • 添加元素对于复杂度(复杂度为:2*logn + 1 +logn,即o(logn)):
        • 第一步是肯定要插入结点的双亲,在最坏状况下,要从堆的右下结点往上遍历到根,而后再向下到堆的左下结点,时间复杂度为2*logn
        • 下一步是插入新结点,时间复杂度为常量
        • 最后一步是重排序,最多须要logn次操做
        • heapifyAdd未执行双亲与孩子的完整互换,只是把双亲元素向下平移到正确的插入点,而后把新值赋给该位置。但它提升了效率,由于减小了在堆的每一层上要执行的赋值次数。
    • removeMin 操做
      • 达到3个目的:用存储在最末结点处的元素替换存储在根处的元素;对堆重排序;返回初始的根元素。
      • 其使用了两个私有方法
        • getNewLastNode:它返回一个指向某一结点的引用,该结点是新的最末结点
        • heapifyRemove:进行重排序(从根向下)
      • 删除根元素对于复杂度(复杂度为:2*logn + logn + 1,即o(logn))
        • 第一步是替换元素,其时间复杂度为常量
        • 第二步是重排序(根往下到叶子),时间复杂度为logn
        • 第三部为肯定新的最末结点,和以前相同为2*logn
    • findMin操做
      • 该元素在堆根处,只需返回根处便可
      • 复杂度为o(1)
  • 用数组实现堆
    • 在二叉树的数组实现中,树的根位于位置0处,对于每一结点n,n的左孩子将位于数组的2n+1位置处,n的右孩子将位于数组的2(n+1)位置处java

    • addElement操做
      • 达到3个目的:在恰当位置处添加新结点;对堆进行重排序;将count递增1(我认为缘由是数组是有容量的,元素增多,要给它空间)
      • 其中有一个私有方法
        • heapifyAdd:进行重排序
      • 添加元素对于复杂度(复杂度为:1+logn,即o(logn))
        • 不须要肯定新结点的双亲,由于会自动根据位置进行放,可是 其余的步骤和链表相同。
        • 数组实现的效率更高些,但复杂度相同为o(logn)
    • removeMin操做
      • 达到3个目的:用存储在最末元素处的元素替换存储在根处的元素;对堆进行重排序;返回初始的根元素
      • 其中有一个私有方法
        • 最末一个元素是存储在数组的count-1位置处的(count是全部的元素值)
        • heapifyRemove:进行重排序
      • 删除元素对于复杂度(复杂度为:logn+1,即o(logn))
        • 不须要肯定新的最末结点
    • findMin操做
      • 该元素为在根处,因此在数组的0位置处
      • 复杂度为o(1)
  • 使用堆:堆排序老师上课用的PPT,我以为上面的堆排序过程很详细,并且易懂
    • heapSort方法的两部分构成:添加列表的每一个元素,而后一次删除一个元素git

    • 就堆排序来讲,老师在上课的时候讲的很详细,并且由于它是有最小堆和最大堆的,根部要不是最小元素,要不是最大元素,所以,堆排序的关键就是经过不断的移动,将最值放在根处,而后利用remove根处元素的方法,将元素删除出来,再对剩余的堆进行重排序,而后继续删除根部,而这个过程,每删除的元素排列出来就是咱们所须要的升序或者降序,即堆排序完成算法

    • 堆排序咱们也能够用数组的知识进行理解。由于咱们在数组实现堆时,已经知道了对于一个根结点,其左右孩子的肯定所在位置,因此咱们能够利用比较和互换,进行排序,其实原理和上一条是相同的。api

    • 不管是用列表仍是数组进行堆排序,他们的复杂度相同,都是o(nlogn)

      数组

      • 对于列表进行堆排序来讲:在前面的学习中,咱们知道,不管是addElement仍是removeMin它们的复杂度都是o(logn)。可是咱们要注意的是,这个复杂度是在添加或者删除一个元素的状况下的复杂度。而咱们进行排序的时候,是须要添加且删除n个元素的,所以,咱们分别要进行这两个操做n次,以知足对n个元素进行排序。因此最终复杂度为2nlogn,即o(nlogn)数据结构

      • 对于数组进行堆排序来讲:从数组中第一个非叶子的结点开始,将它与其孩子进行比较和互换(若有必要)。而后在数组中日后操做,直到根。对每一个非叶子的结点,最多要求进行两次比较操做,因此复杂度为o(n)。可是要使用这种方式从堆中删除每一个元素并维持堆的属性时,其复杂度仍为o(nlogn)。所以,即便这种方式的效率稍好些,约等于2*n+logn,但其复杂度仍为o(nlogn)。学习

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

  • 问题1:书中对于优先级队列的内容其实挺简略的,因此我上网找一下优先级队列的内容
  • 问题1解决方案:
    队列就是先进先出的一种形式,而优先级实际上就是根据某种标准进行排序,高级的就先排,对于相同级别的就根据先进先出的队列的要求进行排序,优先级队列也叫优先权队列。
    对于优先级队列的特色:
    1.优先级队列是0个或多个元素的集合,每一个元素都有一个优先权或值。
    2.当给每一个元素分配一个数字来标记其优先级时,可设较小的数字具备较高的优先级,这样更方便地在一个集合中访问优先级最高的元素,并对其进行查找和删除操做。
    3.对优先级队列,执行的操做主要有:(1)查找,(2)插入,(3)删除。
    4.在最小优先级队列中,查找操做用来搜索优先权最小的元素,删除操做用来删除该元素。
    5.在最大优先级队列中,查找操做用来搜索优先权最大的元素,删除操做用来删除该元素。
    注:咱们在删除以后,要根据要求对以后的元素进行从新的排列,这个时候,咱们可能出现多种的相同优先权,因此,这个时候就应该根据队列的要素,进行先进先出的进行排序,所以这也提醒咱们,咱们在写代码时,咱们要对进入队列的顺序进行记录。
    6.插入操做均只是简单地把一个新的元素加入到队列中。测试

  • 问题2:我和曾程在宿舍看书的时候,看到getNextParentAdd这段代码不理解,我俩都处于有点蒙圈的状态。
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;
    }
  • 问题2解决方案:后来晚上听馨雨和仇夏讨论的时候,我俩也去听了下,就懂得了。
    下面是一个本身画的图的过程:

代码调试中的问题和解决过程

  • 问题1:在进行ArrayHeap的测试时,出现这样的状况,它删除以后,后面老是多出来一个数字,不知道为何?
    this

  • 问题1解决方案:后来我问了谭鑫,谭鑫说,书中的removeMin少写了一条语句,就是
tree[count - 1] = null;

而后我把它加上就正常了

后来他给我讲缘由:

T minElement = tree[0];//最小的元素是根结点,也就是数组的0位置处
        tree[0] = tree[count-1];//这个时候,将最末叶子结点放在了根结点处,准备进行重排序
        tree[count-1] = null ;//将放在上面的那个最末叶子结点去掉,不然就会多出来
        heapifyRemove();//进行重排序

代码托管

上周考试错题总结

  • 这个是马虎的,我后来看IDEA知道了compareTo返回的是boolean型

  • 选择排序算法经过反复地将某一特定值放在它的列表中的最终已排序位置从而完成对某一列表值的排序

  • 插入排序算法经过反复地将某一特定值插入到该列表某个已排序的子集中来完成对列表值的排序

结对及互评

评分标准

  • 博客中值得学习的或问题:
    • 课本内容总结的很详细
  • 代码中值得学习的或问题:
    • 有的问题我没遇到过,看到他的也算是种收获

点评过的同窗博客和代码

  • 本周结对学习状况
    • 20172325
    • 结对学习内容
      • 一块儿学习了十二章的内容
      • 共同窗习了堆的排序
      • 讨论了堆的添加和删除

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

第十二章老师讲的比较简略,主要讲了堆排序的内容,说是颇有用的,并且我也听懂了,哈哈哈!

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 0/0 1/1 6/6
第二周 985/985 1/1 18/24
第三周 663/1648 1/1 16/40
第四周 1742 /3390 2/2 44/84
第五周 933/4323 1/1 23/107
第六周 1110/5433 2/2 44/151
第七周 1536/6969 1/1 56/207
第八周 1403/8372 2/2 60/267

参考资料

相关文章
相关标签/搜索