规则
排序成本模型:在研究排序算法时,我们需要计算比较和交换的数量。对于不交换元素的算法,我们会计算访问数组的次数。
排序算法可以分为两类:
- 除了函数调用所需的栈和固定数目的实例变量之外无需额外内存的原地排序算法
- 需要额外内存空间来存储另一份数组副本的其他排序算法
选择排序
- 首先,找到数组中最小的那个元素。
- 其次,将它和数组的第一个元素交换位置。(如果第一个元素最小,那么它和自己交换位置)
- 再次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。
- 如此往复,不断在剩余元素中选出最小者,直到将整个数组排序。
命题A:对于长度为 N 的数组,选择排序大约需要 N^2/2 次比较和 N 次交换。
选择排序的特点:
运行时间和输入无关。
已经有序的数组或是主键全部相等的数组和一个元素随机排序的数组所用的排序时间竟然一样长!
数据移动次数最少。
交换次数和数组的大小是线性关系。
插入排序
为了给要插入的元素腾出空间,需要将其余所有元素都在插入之前向右移动一位。
插入排序所需的时间取决于输入元素的初始顺序。
命题B:对于随机排列的长度为 N 且主键不重复的数组,
- 平均情况下插入排序需要 ~N^2/4 次比较 以及 ~N^2/4 次交换。
- 最坏情况下需要 ~N^2/2 次比较和 ~N^2/2 次交换。
- 最好情况下需要 N-1次比较和 0 次交换。
典型的部分有序的数组:
- 数组中每个元素距离它的最终位置都不远
- 一个有序的大数组接一个小数组
- 数组中只有几个元素位置不正确
命题C:插入排序需要的交换操作和数组中倒置的数量相同,需要的比较次数 >= 倒置的数量,<= 倒置数量加上数组大小-1。
插入排序对于部分有序数组和小规模数组十分高效。
希尔排序
希尔排序交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序。
希尔排序的思想是使用数组中任意间隔为 h 的元素都是有序的。这样的数组被成为 h 有序数组。
排序之初,各个子数组都很短,排序之后子数组都是部分有序的,这两种情况都很适合插入排序。
希尔排序可以用于大型数组,对任意排序(不一定是随机的)的数组表现也很好。
希尔排序的运行时间达不到平方级别。最坏情况下,比较次数和 N^(3/2) 成正比。
希尔排序对于中等大小的数组的运行时间是可接受的。代码量很小,而且不会占用额外内存。