2018-2019-20172329 《Java软件结构与数据结构》第三周学习总结
教材学习内容总结
《Java软件结构与数据结构》第五章-队列
一、概述
- 1、队列是什么?
队列是种线性集合,其元素从一端加入,从另一端删除;注:队列是按照先进先出的方式处理的。从队列中删除元素的次序,与放置元素的次序是一样的。
- 2、队列的构成
(1)方法:
操作 | 描述 |
---|---|
enqueue | 向队列末端添加一个元素 |
dequeue | 从队列前段删除一个元素 |
first | 考察队列前端的那个元素 |
isempty | 判定队列是否为空 |
size | 确定队列的元素数目 |
(2)过程
- 3、其他内容
(1)队列是一种可存储重复编码密钥的便利集合。
(2)通常用表示排队的队列来实现模拟。
二、用链表实现队列
- 1、概述
(1)那两个分别指向链表首元素、链表末元素的引用方便队列的链表实现。
(2)为了从链表的末端出列,必须把一个临时变量设置为指向链表末端的元素。
- 2、链表实现的过程图
- 3、enqueue操作
(1)enqueue操作要求将新元素放到链表末端。
(2)注:新结点的next引用无需显示的进行设置。
- 4、dequeue操作
(1)enqueue和dequeue操作作用于队列的对立端。
三、用数组实现队列
- 1、概述
(1)由于队列操作会修改集合的两端,因此将一端固定于索引0处要求移动元素。
(2)非环形数组实现的元素移位,将产生O(n)的复杂度。
(3)把数组看成环形的,可以出去在队列的数组实现中把元素移位的需要。
- 2、环形数组
(1)概述:简单来讲就是如果数组的最后一个索引后面跟的是第一个索引,就可用作环形数组。
(2)注:当添加和删除元素时,不需要移动哪个元素,但是一定要小心维护front和rear的值。
教材学习中的问题和解决过程
- 问题1:在用链表实现队列的时候,我们所需要的有两个front结点和rear的结点,但是他们是否实际存在,或者另一种表达就是是否可以给其赋值?
- 问题1解决过程:
(1)首先,对于只有一端的队列而言,符合的应当是先进先出的原则,所以最先进入的就应当是最先出去的元素,在进入多个元素以后,这一个先进入的元素就会变成一个队列的队尾,所以在书中有这样一句话:
“为了从链表的末端出列,必须把一个临时变量设置为指向链表末端的元素,然后把tail指针设置为指向当前末端之前的结点。”
所以对于队尾来讲,有这样一个rear的结点进行“管理”,防止元素丢失。
(2)而对于首来讲,更是重要,它需要去确定每一个元素的位置,防止整个队列元素的丢失。所以下图的展示很能够体现队列的这样一种不同于链表的结构。
简单表达就是头结点其实相当于队列第一个元素所在结点的前一个结点,通过其来确定整个队列内部元素的位置
- 问题2:对于循环数组整个流程到底是如何进行的?
- 问题2解决方案:(该解决方法为搬运,来源已在参考资料中显示,参考原文请到参考文献查看)
- 在学习了循环数组以及循环队列以后,我发现其原理很相似,所以进行图示,方便理解;
(1)在我们数组的实现方式中,用两个int型变量用于记录队头和队尾的索引。
图一:
(2)一个队列的初始状态,head和tail都指向初始位置(索引为0处)。head永远指向该队列的队头元素,tail则指向该队列最后一个元素的下一位置,当有入队操作时:
图2:
图3:
(3)当有出队操作时:
图4:
(4)当遇到出队操作时,head会移向下一元素位置。当然,对于这种方式入队和出队,队空的判断条件显然是head=tail,队满的判断条件是tail=array.length(数组最后一个位置的下一位置)。显然,这种结构最致命的缺陷就是,tail只知道向后移动,一旦到达数组边界就认为队满,但是队列可能时刻在出队,也就是前面元素都出队了,tail也不知道。例如:
图5:
(5)此时tail判断队满,我们暂时认为资源利用是可以接受的,但是如果接下来不断发生出队操作:
图6:
(6)此时tail依然通过判断,认为队满,不能入队,这时数组的利用率我们是不能接受的,这样浪费很大。所以,我们引入循环队列,tail可以通过mode数组的长度实现回归初始位置,下面我们具体来看一下。
按照我们的想法,一旦tail到达数组边界,那么可以通过与数组长度取模返回初始位置,这种情况下判断队满的条件为tail=head
图7:
(7)此时tail的值为8,取模数组长度8得到0,发现head=tail,此时认为队列满员。这是合理的,但是我们忽略了一个重要的点,判断队空的条件也是head=tail,那么该怎么区分是队空还是队满呢?解决办法是,空出队列中一个位置,如果(tail+1)%array.length=head,我们就认为队满,下面说明其合理性。
上面遇到的问题是,tail指向了队尾的后一个位置,也就是新元素将要被插入的位置,如果该位置和head相等了,那么必然说明当前状态已经不能容纳一个元素入队(间接的说明队满)。因为这种情况是和队空的判断条件是一样的,所以我们选择舍弃一个节点位置,tail指向下一个元素的位置,我们使用tail+1判断下一个元素插入之后,是否还能再加入一个元素,如果不能了说明队列满,不能容纳当前元素入队(其实还剩下一个空位置),看图:
图8:
(8)tail通过取模,回归到初始位置,我们判断tail+1是否等于head,如果等于说明队满,不允许入队操作,当然这是牺牲了一个节点位置来实现和判断队空的条件进行区分。上述文字基本完成了队循环队列的理论介绍,下面我们看在Java中对该数据结构的具体实现是怎样的。
代码调试中的问题和解决过程
问题1:最近在编写代码的过程中,感觉遇到的最多的就是空指针这个异常,如下图,我在这里分享一些我一般而言解决这一系列问题的一些技巧。
问题1解决方案:
(1)首先,在下面的地方可以看见出错的地方在哪里,因为为什么会出现空指针呢,就是因为我们想要索引的地方就是一个null,所以肯定就会出现异常,因此呢,就一般而言我就再找一个新指针,作为一个测试指针,找到出错在哪一步。(这里肯定会有人说为什么不用bug,因为我觉得这个找错也是一种方法,但是就我个人而言,我觉得bug一点一点的又点慢,所以就找了新方法)
(2)然后我一般而言会在循环里找问题,因为有时候就是因为多移了一步可能就导致了这一个问题,所以我们可以给他减或加一次循环进行查看,结果是否可以成功输出。
上周考试错题总结
由于上周没有进行测试,所以没有错题总结
代码链接
结对及互评
- 本周结对学习情况
- 博客中值得学习的或问题:
- 内容详略得当;
- 代码调试环节比较详细;
- 基于评分标准,我给本博客打分:5分。得分情况如下:
- 正确使用Markdown语法(加1分):
- 模板中的要素齐全(加1分)
- 教材学习中的问题和解决过程, 一个问题加1分
-
代码调试中的问题和解决过程, 一个问题加1分
- 博客中值得学习的或问题:
- 内容详略得当;
- 代码调试环节比较详细;
- 基于评分标准,我给本博客打分:9分。得分情况如下:
- 正确使用Markdown语法(加1分):
- 模板中的要素齐全(加1分)
- 教材学习中的问题和解决过程, 一个问题加1分
- 代码调试中的问题和解决过程, 一个问题加1分
感悟
我觉得这个中秋节过的非常充实,希望自己自己尽快再找到更好的状态去面对新的学期,让自己可以学到更多知识,可以让自己在这学期可以有更多的收获。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | |
---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 |
第一周 | 0/0 | 1/1 | 6/6 |
第二周 | 1313/1313 | 1/2 | 20/26 |
第三周 | 901/2214 | 1/3 | 20/46 |
补充作业
技能 | 课前评估 | 课后评估 |
---|---|---|
对编程整体的理解 | 2 | 6 |
架构设计、模块化设计、接口设计 | 2 | 6 |
效能分析及改进 | 2 | 6 |
处理大数据 | 1 | 6 |
处理命令行参数和文件系统 | 1 | 6 |
自主学习的能力 | 5 | 7 |