走了很多的弯路,现在认识到数据结构与算法在一个软件开发人员的知识结构中的地位。 以前上学时学的一塌糊涂,现在回过头来补。希望自己吸取教训:( 。 这些基础算法在很大程度上是对人的逻辑思维的一个提高锻炼。记得一篇文章中说过:软件开发最重要的就是 逻辑思维能力和描述能力。而各种语言,开发工具只是变着法的来最大限度方便地来实现你的思想的。
ok ,废话少说!下面就对这几天学习的排序算法做个小结(虽然网上关于这方面的知识一大堆,但是通过自己的总结更能加深理解:)
排序,在软件开发中是一个重要的操作,由于待排序的记录的数量不同,使得排序过程中涉及到的存储器不同,可以分为: 内部排序和外部排序。
下面咱们先讨论内部排序
按照排序的工作量来区分,一般可以分为 :
1)简单排序方法, 其时间复杂度为O(n^2).
2)先进排序算法,其时间复杂度为O(nlogn).
3)基数排序方法,其时间复杂度为O(d * n).
待排序的记录序列可能有三种方式:
1)待排序的记录存放在地址连续的一组存储单元中。这种方式中,记录之间的次序关系由存储位置决定,实现排序必须借助移动记录。
2)待排序的记录存放在静态链表中。记录之间的次序关系由指针指示,实现排序则不需要移动记录,仅修改指针即可。这种情况又称链表排序。
3)待排序的记录存放在一组地址连续的存储单元中,只不过在每个记录中设置了一个”指针“(地址向量 ),用来记录各记录的相对位置,在排序的过程不移动记录,只是改变这些地址向量中这些记录的“地址”, 在排序之后再按照这些地址向量中的值调整记录的存储位置。
注: 初了掌握算法外,最重要的是掌握算法所依据的具体原则,以利于学习和创造更适合的算法:)
下面就从内部排序,存储方式为第一种的情况来讨论具体的排序算法。
1:插入排序
1.1 直接插入排序
思想:对a[n]排序,从 2~n中按序每次取一个记录,插入到前面有序的记录组中。开始时有序记录选为第1个记录。
当记录的关键字为正序时,需要比较的次数达到最小值:n-1。 当为逆序时(最差情况下)为(n+2)(n-1)/2 (即是 i ~ n 的 ( i + 1) 的和)。取最大值和最小值的平均值的话约为(1/4)n2
直接插入排序虽然简单,当n是一个小数字的时候是一种很好的排序算法, 但是当n 很大的时候, 就不适合了。 此时得从减少”比较“ 和" 移动" 的方向上来改进此算法, 此时就得到 折半插入排序。
1.2 折半插入排序
思想: 在直接插入排序的基础上, 如果判断当前的记录需要插入到前面的以有序的组中时,在以有序组中用折半 查找的方法来找到所要插入的位置, 这种方法比一个一个比较来寻找要插入的位置要效率高。 是从减少”比较“ 的角度对直接插入排序的改进。
上述排序算法所需要的附加存储空间和直接插入排序相同,而时间上只是少了比较的次数,而移动的次数不变, 所以时间复杂度还是O(n2 ).
如果上述的算法在有序的情况下时间复杂度由O(n2 )会减小到O(n), 另一方面由于直接插入排序的n小的时候效率还是可以的。由此出发,可得到shell排序。
1.3 shell 排序
思想:将整个待排的记录分为若干个段, 先对每个段进行直接插入排序, 之后再对所有的进行一次直接插入排序。
本算法在直接插入排序的基础上做了如下修改:
:前后记录位置的增量由1变为di (增量数组中的值)。
增量序列可以多种取法, 但是有要求: 增量序列中没有除1之外的公因子,并且最后一个增量为1(为了在“基本有序”的基础上做一次直接插入排序)。
2 快速排序
首先是最简单的一种: 冒泡排序。
基本操作为:序列中相邻两个整数的交换。最坏情况下(逆序)的需进行n-1趟排序,进行i 从n ~ 2 次的(i-1)比较。时间复杂度为 T(n) = O(n2 ).
2.2 快速排序
思想: 通过一趟排序将待排记录分割成独立的两部分,其中一部分的关键字均比另一部分的关键字小,则可分别对这两部分继续利用这种方法来排序,以达到整体有序的目的。