本周学习了第12章优先队列与堆php
操做 说明 addElement 将给定元素添加到该堆中 removeMin 删除堆的最小元素 findMin 返回一个指向堆中最小元素的引用
如图是一个最小堆
html
addElement方法将给定的Comparable元素添加到堆中的恰当位置处,且维持该堆的彻底性属性和有序性属性node
若是一棵二叉树是平衡的,及全部叶子都位于h或者h-1层,其中h为log2n,n是树中的元素数目,以及全部h层中的叶子都位于该树的左边,那么该树就被认为是彻底的。由于堆是一棵彻底树,因此对于新插入的结点只存在一个正确的位置,要么是h层左边的下一个空位置,要么就是h+1层左边的第一个位置(若是h层是满的话)git
removeMin操做将删除最小堆中的最小元素并返回他,最小堆中的元素便是它的根结点,为了保持树的合法性,须要有一个能替换根的合法元素,且它是树中最末一片叶子上的元素。将最末一片叶子移至根处以后,又须要将该堆进行从新排序。排序方法须要将该结点与最小孩子进行比较而后逐渐下沉到合适的位置。借用上图,若是将根结点1删去,那么最末叶子6就将成为新的根结点,它将与二、5进行比较最终落在5如今的位置,而2将成为新的根结点。web
问题1:链表实现堆的过程当中的addElement操做第一步要肯定要插入结点的双亲,为何在最坏的状况下要从堆的右下结点遍历到根结点以后还要再从根结点遍历到堆的左下结点?数组
问题1解决方案:这个问题我思考了小半个小时,添加的第一步须要肯定插入结点的双亲,由于须要比较双亲结点的值与新结点的值,决定新结点是否要上浮。因此最坏的状况应该是新结点一直上浮到根结点,此时按最小堆的定义来看,添加元素这一操做应该是中止了,由于堆顶是最小元素了,它的左孩子和右孩子的值都应该比它要小,因此不须要继续遍历它的左孩子直到左下结点了吧。和同窗讨论以后,才发现个人理解错在哪里了。它这里指的是遍历的最坏状况须要从右下结点一直到根再到左下结点,而不是结点互相之间的比较须要让结点上浮以后再次下沉(事实上跟我分析的同样,他也没法作到)。它这里指的是查找肯定新结点的双亲结点的最坏状况
如上丑图,添加元素时恰好碰见满树的状况,须要从右下最后一片叶子开始找起,一直到左下结点,才最终肯定要插入的元素的双亲结点。数据结构
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;
首先教材讲到,这是一个返回指向插入结点的双亲结点的引用。因此就容易理解到,这个方法就是肯定新插入结点的双亲结点。也就经过此来决定新添加元素的位置。
一开始,新设一个变量result指向lastNode,即指向最后一片叶子的引用。
接下来经过判断最后一片叶子的状况来肯定插入结点的双亲结点,当最后一片叶子不是根结点且同时不是左孩子的时候,就将result的父结点付给result,直到不知足两个条件之一跳出循环。当最后一片叶子是根结点时,已经肯定了新结点的双亲结点,能够进入下一步,而若是最后一片叶子是右结点,就说明当前父结点是满的,不能再在当前父结点下添加新元素,因此将result指向result的父亲,方便寻找一个没有满的父结点。下一步,此时result跳出while循环,要么它是根结点,要么它是左孩子。若是它是左孩子,即进入if语句内,判断它的兄弟结点是否为null,若是返回true,那么新添加元素的双亲结点就肯定了是result的父结点,而新结点将做为result的右孩子添加到堆中,若是返回false,result将指向这个右孩子,并找到它的最左下的位置添加。若是result是指向根结点的,那么也一直循环到它的最左下位置,添加新元素。
这个问题的解决参考了于欣月同窗的博客,她在解释时运用了图文结合的形式,对我理解该问题起了很大帮助ide
问题1:测试LinkedHeap类,实现层序输出、前序中序后序各类输出,很不巧的是它出现了乱码的状况
学习
问题1解决方案:这个问题的出现充分说明我还没能掌握迭代器的精髓,首先方法的使用就是彻底错误的,我还把它看成简单的toString方法在加以使用。因此天然输出不来须要的结果,标准的应该是如图,先设置一个迭代器的对象,经过for循环一个一个调用迭代器里的内容,如图
测试
排序方法 时间复杂度 选择排序 O(n^2) 插入排序 O(n^2) 冒泡排序 O(n^2)
在个人鞭策与督促之下,某同窗的博客又恢复到了以往的超高水平。(他在教材问题中提到了一个
实现优先级队列的二叉堆、d堆、左式堆、斜堆、二项堆都是什么意思?
我翻了一下书,好像没有找到哪里提到了这些概念,因此若是是查找的资料里提到的,但愿也能贴出连接来,让我学习学习,不至于落下太多
方艺雯的博客写的很棒,提出了不少我没考虑过的问题。
基于评分标准,我给谭鑫的博客打分:6分。得分状况以下:
正确使用Markdown语法(加1分)
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 一个问题加1分
代码调试中的问题和解决过程, 三个问题加3分
基于评分标准,我给方艺雯的博客打分:8分。得分状况以下
正确使用Markdown语法(加1分):
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 两个问题加2分
代码调试中的问题和解决过程, 四个问题加4分
这周的教材学习比较容易,因此花的时间相对较少,可是实验使人难受。
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 8/8 | |
第二周 | 470/470 | 1/2 | 12/20 | |
第三周 | 685/1155 | 2/4 | 10/30 | |
第四周 | 2499/3654 | 2/6 | 12/42 | |
第六周 | 1218/4872 | 2/8 | 10/52 | |
第七周 | 590/5462 | 1/9 | 12/64 | |
第八周 | 993/6455 | 1/10 | 12/76 | |
第九周 | 1192/7467 | 2/12 | 10/86 |