LintCode 关于排序问题的总结

来源:互联网 发布:淘宝电子烟店铺排名 编辑:程序博客网 时间:2024/06/05 01:55

排序的基本概念

排序:给定一组记录的集合{r1, r2, ……, rn},其相应的关键码分别为{k1, k2, ……, kn},排序是将这些记录排列成顺序为{rs1, rs2, ……, rsn}的一个序列,使得相应的关键码满足ks1≤ks2≤……≤ksn称为升序)或ks1≥ks2≥……≥ksn称为降序)。

正序:待排序序列中的记录已按关键码排好序。

逆序(反序):待排序序列中记录的排列顺序与排好序的顺序正好相反。

:在排序过程中,将待排序的记录序列扫描一遍称为一趟。

  通常,一次排序过程需要进行多趟扫描才能完成。

排序算法的稳定性:

假定在待排序的记录集中,存在多个具有相同键值的记录,

若经过排序,这些记录的相对次序仍然保持不变,

即在原序列中,ki=kjrirj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。

对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性;
而对于稳定的排序算法,必须对算法进行分析从而证明稳定的特性。
需要注意的是,排序算法是否为稳定的是由具体算法决定的。
–不稳定的算法在某种条件下可以变为稳定的算法,
而稳定的算法在某种条件下也可以变为不稳定的算法。

排序的分类-根据排序数据在内存中还是在外存中:

1.内排序:在排序的整个过程中,待排序的所有记录全部被放置在内存中

2. 外排序由于待排序的记录个数太多,不能同时放置在内存,而需要将一部分记录放置在内存,另一部分记录放置在外存上,整个排序过程需要在内外存之间多次交换数据才能得到排序的结果。

排序的分类-根据排序过程中所进行的基本操作分:

1. 基于比较:基本操作——关键码的比较和记录的移动,其最差时间下限已经被证明为Ωnlog2n)。

2. 不基于比较:根据关键码的分布特征。比如,桶式排序,基数排序(多关键字排序)

基于比较的内排序

1. 插入排序

2. 交换排序

3. 选择排序

4. 归并排序

不基于比较的内排序

1. 分配排序 

  桶式排序

  基数排序

1.时间复杂性:基本操作
内排序在排序过程中的基本操作:
比较:关键码之间的比较;
移动:记录从一个位置移动到另一个位置。

2.空间复杂性: 辅助存储空间

辅助存储空间是指在数据规模一定的条件下,除了存放待排序记录占用的存储空间之外,执行算法所需要的其他存储空间。

入类排序

插入排序的主要操作是插入

其基本思想是:

每次将一个待排序的记录按其关键码的大小插入到一个已经排好序的有序序列中,直到全部记录排好序为止。

插入类排序方法有以下两种:

直接插入排序

希尔排序

直接插入排序算法性能分析

空间性能:需要一个记录的辅助空间。

直接插入排序算法是一种稳定的排序算法。

Ø直接插入排序算法简单、容易实现,适用于待排序记录基本有序或待排序记录个数较小的情况。
Ø当待排序的记录个数较多时,大量的比较和移动操作使直接插入排序算法的效率降低。

希尔排序

基本思想:

将整个待排序记录分割成若干个子序列,

在子序列内分别进行直接插入排序,

待整个序列中的记录基本有序时,对全体记录进行直接插入排序。

交换排序

交换排序的主要操作是交换,其主要思想是:在待排序列中选两个记录,将它们的关键码相比较,如果反序(即排列顺序与排序后的次序正好相反),则交换它们的存储位置。

交换类排序的两种方法

冒泡排序

快速排序

冒泡排序

基本思想:两两比较相邻记录的关键码,如果反序则交换,直到没有反序的记录为止。

快速排序的基本思想

首先选一个轴值(即比较的基准),

通过一趟排序将待排序记录分割成独立的两部分,

前一部分记录的关键码均小于或等于轴值,

后一部分记录的关键码均大于或等于轴值,

然后分别对这两部分重复上述方法,直到整个序列有序。

选择排序

选择排序的主要操作是选择,其主要思想是:每趟排序在当前待排序序列中选出关键码最小的记录,添加到有序序列中。

堆排序

堆是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(称为小根堆),或每个结点的值都大于或等于其左右孩子结点的值(称为大根堆)。

基本思想:

首先将待排序的记录序列构造成一个堆(大顶堆)

此时,选出了堆中所有记录的最大者,然后将它从堆中移走,

并将剩余的记录再调整成堆,

这样又找出了次大的记录,以此类推,直到堆中只有一个记录。

归并排序

归并:将两个或两个以上的有序序列合并成一个有序序列的过程。

归并排序的主要操作是归并,其主要思想是:将若干有序序列逐步归并,最终得到一个有序序列。

二路归并排序

基本思想:

将一个具有n个待排序记录的序列看成是n个长度为1的有序序列,

然后进行两两归并,

得到n/2个长度为2的有序序列,

再进行两两归并,得到n/4个长度为4的有序序列,

……

直至得到一个长度为n的有序序列为止。



最后说一下我对几种排序的理解和看法。

插入排序是最好理解的算法,把无序的数列中所以元素插入到一个有序数列中,让它待在它该在的位置,

左边的比他小,右边的比他大。

冒泡排序就如其名一样,以正序为例,把小元素像冒泡泡一样往前跑,通过两两交换最终小的在前大的在后。

希尔排序把数列分成几个小块,而且是隔着几个元素分的,通过这些小块的基本有序最终达成总体的基本有序。

堆排序类似于二叉搜索树,左子树的小右子树的大,进而达到整体有序。

归并排序和希尔排序有些相似之处,不同的在于是按照当前的顺序划分为小块,通过小块融合成大块保持有序最终

达到整体的有序。

综上所述,简单的排序通过比较和交换元素进行,不单有比较的时间复杂度,还有交换的空间复杂度。而快速

排序通过把大问题缩小化,先小范围内基本有序,最终合并为一个有序的整体。简单有序胜在过程很好理解,数据量

小的情况下通过观察都可以得出结论,而快速排序过程复杂,然而只要小范围的有序做好大范围自然也就水到渠成了。