20172323 2018-2019-1 《程序设计与数据结构》第五周学习总结
20172323 2018-2019-1 《程序设计与数据结构》第五周学习总结
教材学习内容总结
本周学习了第六章排序与查找
一些概念
- 静态方法可以通过类名来激活,不用特意实例化该类的一个对象调用该静态类的方法。在方法声明中,通过使用static修饰符就可以把它声明为静态的
- 创建泛型方法,只需在方法头前的返回类型前插入一个泛型声明即可。泛型声明必须在返回类型之前,这样泛型才可作为返回类型的一部分
public static <T extends Comparable<T>> boolean
linearSearch (T[] data, int min, int max, T target)
查找
- 在某个项目组中寻找某一指定目标元素,或确定该指定目标不存在,是为查找。进行查找的项目组被称为查找池
- 线性查找法:从头开始依次比较每一个值,直到找到目标元素,或者得出不存在该目标值的结论,这种方式称为线性查找(linear search)
- 二分查找(折半查找):当查找池中的项目组是已排序的,那么利用二分查找将会更有效率。
- 二分查找的思路: 二分查找从排序列表的中间开始查找,如果中间元素不是目标元素,根据两个元素的大小关系,再判断从列表的前一半或是后一般进行查找。每次的查找都是从当前一串数字的中间元素开始的。直到最后找到该元素或是没有找到抛出一个信息。
- 二分查找的每次比较都会删除一半的可行候选项,当查找池中有偶数个待查找值时,选择的是两个中间值的第一个。
- 二分查找的复杂度是对数级的,这使得它对于大型查找池非常有效率。线性查找具有线性时间复杂度O(n),二分查找具有时间复杂度O(log2n)。
排序
-
基于某一标准,将某一项目组按照某个规定排序排列
-
选择排序法
- 反复寻找当前列表的最小值,然后将其放在列表的前端。
- 反复寻找当前列表的最小值,然后将其放在列表的前端。
-
插入排序法
- 将数字插入前端已排序的列表的合适位置直至排序完成。
- 将数字插入前端已排序的列表的合适位置直至排序完成。
-
冒泡排序法
- 反复比较相邻元素的大小关系进行移位操作直至排序完成
- 反复比较相邻元素的大小关系进行移位操作直至排序完成
-
快速排序法
- 选择一个列表元素进行分区元素,然后对两个分区进行递归排序直至排序完成(一个分区只含有一个元素2)。
- 排序时两个分区同时进行查找,一旦两边都找到一个元素,将两者进行互换
-
归并排序法
- 将列表递归式分成两半直至每一子列表都含有一个元素,然后再归并到一个排序顺序中完成排序
- 将列表递归式分成两半直至每一子列表都含有一个元素,然后再归并到一个排序顺序中完成排序
-
基数排序法
- 基数排序基于队列处理
- 基数排序基于队列处理
教材学习中的问题和解决过程
- 问题1:选择排序的代码实现中出现了
public static <T extends Comparable<? super T>> void selectionSort (T[] data)
之中<? super T>表示的是什么意思 - 问题1解决方案:查阅资料在网上找到了一个通俗易懂的回答,大致上把<? super T>三个部分都讲得比较清楚了。按照我的理解,在这里?代表的是通配符,这一整串代表的是一个下界通配符,用在此处代表Comparable接口中的泛型元素都是T或者T的父类,这样就放松了存入数组的类型限制,但是引起的缺点就是往外读取元素就会变得困难,可能使元素类型信息丢失。
- 问题2:几种排序方法时间复杂度的比较
- 问题2解决方案:
排序方法 | 时间复杂度 |
---|---|
选择排序 | O(n^2) |
插入排序 | O(n^2) |
冒泡排序 | O(n^2) |
快速排序 | O(n*log2n) |
归并排序 | O(nlog2n) |
基数排序 | O(n) |
三种顺序排序方法都使用了内外两层循环进行排序操作,所以时间复杂度都为nxn-->O(n^2);
快速排序和归并排序两种对数排序在排序中采取了递归的方法,因此在元素比较中只用到了大约nlog2n次比较,时间复杂度为O(log2n);还有一种特殊的基数排序,因为在排序过程中不涉及到元素之间的比较,只需要将元素在队列之间进行移动操作,操作时只用遍历数据即可,因此可以用c*n来表示(c是常数),所以时间复杂度为O(n)。
代码调试中的问题和解决过程
- 问题1:PP9.2中间隔排序的思路有些混乱,为什么每次迭代完成之后i要减少某个大于1的数量直至i的值小于1.
- 问题1解决方案:在网上没能找到关于间隔排序的资料,所以不太懂原理,应该也和冒泡排序差不太多吧,就按照题目的要求拼好了代码,可运行出来的结果排序似乎并没有完成。
假设现在有一个长度为6的数组,第一次的i为3,每一次迭代后i减少的值为2,那么在第一次迭代中,第一个元素与第三个元素进行比较,第二个元素与第四个元素进行比较,第三个元素与第五个元素进行比较,第四个元素与第六个元素进行比较,第一次迭代结束,i的值为1,第一个元素与第二个元素进行比较...相邻元素分别进行比较,迭代结束,i的值为-1小于1,此时循环结束,排序完成。
如果每次i的值减少1
与题目给的信息恰恰想反,反倒是每次减一时能得出正确的排序,多次修改代码中的间隔值,发现i每次减一时排序都能正确完成但是减二、减三时只能是在部分间隔值的情况下才能排序完成
- 问题2:PP9.3如何用代码实现总的比较次数和总执行时间的计数
- 问题2解决方案:
计时
最开始应用的代码如下
Date da = new Date();
long s1 = da.getTime();
...//具体运行的代码
long s2 = System.currentTimeMills();
System.out.println(s2 - s1);
代码开始运行时记录当前时间,代码结束前再记录一下当前时间,最后s2-s1即为运行时间,思路是没有问题,可是运行结果出来就有点小瑕疵,如图
运行时间全为0且没带单位,我觉得系统并没有错,可能真是运行时间太短吧,小于一秒的计算机就自动四舍五入归为0了(?),我是这样认为的,所以我又寻找到另一种比较精密计量时间的方法
以毫秒为单位计算的:
long startTime = System.currentTimeMillis();//获取当前时间
doSomeThing();
long endTime = System.currentTimeMillis();
System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
以纳秒为单位计算的:
long startTime = System.nanoTime();//获取当前时间
doSomeThing();
long endTime = System.nanoTime();
System.out.println("程序运行时间: "+(end-start)+"ns");
好似万事俱备,运行一下试试,问题还是出现了,毫秒计时依然为0额。
此时我又找到了Date.getTime的说明
Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object,显然这个方法同样是以毫秒为单位来计量代码运行的时间的,之前什么四舍五入的解释就有问题了,在网上寻找答案也只得到一些毫不沾边的东西,有点一筹莫展,后来我再仔细一瞅,发现纳秒计时的方法似乎没有出错啊,于是改成纳秒计时,然后就运行成功???有点莫名其妙。
原以为计时在稀里糊涂之中就可以全部解决了,把五大排序法中分别加上s1、s2,然后运行一下,这次又是归并排序的计时出现了些问题,如图
debug一下,错误应该出在忽略了递归上面,就是计算机每执行一次mergeSort的方法,就得重新开始计时一次,所以最后的结果会输出很多个归并排序的计时,参照快速排序的方法,相当于在归并排序的外面加一层壳专门用来计时,其他也想不出更好的办法了,最终结果如图
比较次数
- 对于选择排序、插入排序和冒泡排序,其内层循环都为比较相邻两元素的大小,外层控制存储的位置,所以只需在内层写入一个计数的变量count,每执行一次内层循环count+1.
- 对于快速排序和归并排序,只要进行了一次compareTo操作count就需要加一,无论是否满足while循环的条件,因此while循环内外都应该有语句count++。
代码托管
上周考试错题总结
上周没有错题哦
结对及互评
-
博客中值得学习的或问题:
- 谭鑫的博客一直保持很高的水准,特别是问题的总结和解决能力都值得学习,能看出来是在用心学习
- 方艺雯的博客教材学习内容总结认真详细,并配有图示和自己的理解,点个赞
-
基于评分标准,我给谭鑫的博客打分:8分。得分情况如下:
正确使用Markdown语法(加1分):
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 三个问题加3分
代码调试中的问题和解决过程, 三个问题加3分 -
基于评分标准,我给方艺雯的博客打分:8分。得分情况如下:、
正确使用Markdown语法(加1分):
模板中的要素齐全(加1分)
教材学习中的问题和解决过程, 两个问题加2分
代码调试中的问题和解决过程, 三个问题加3分
排版精美加1分 -
本周结对学习情况
-
上周博客互评情况
其他
这周在代码学习上还是遇到了一些小的问题,在资料缺乏的情况下,自己动手写代码的能力、分析问题的能力有了一些加强,但还是稍显欠缺,需要继续努力
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 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 |