图解十大排序
3.1 前文回顾
在前俩篇文章中,给大家介绍了一下时间复杂度为O( n2 )的排序方法,大家还记得它们是哪几种排序吗?让我们回顾一下
冒泡排序
选择排序
插入排序
那还有时间复杂度比O( n2 )更低的排序算法吗?今天就让我们来介绍一下
3.2希尔排序
希尔排序是一种插入排序(如果大家忘记插入排序的话可以回去看上一篇文章),它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序,同时该算法是冲破O(n2)的第一批算法之一。大家想一想,在什么情况下,插入排序的工作量会比较小呢?
- 当数组元素较少的时候,插入排序的工作量会 比较小。因为插入排序的时间复杂度是O(n 2),工作量和n 2成正比,如 果n比较小,那么排序的工作量自然会小得多。
- 当数组大部分元素有序的时候,插入排序的工作量也会相对 较小。因为在这种情况下,数组中的元素并不需要进行频繁的比较和 交换。
让我们来看一个例子 给定无序数组 : [3, 5, 2, 6, 4, 8]
先让元素俩俩分组,每俩个元素之间的距离是数组总长度 n
的一半,所以分组跨度是3
如图所示:元素3和6一组,元素5和4一组,元素2和8一组,一共3组
我们对每一组元素进行插入排序,由于每一组元素的数量只有俩个,所以插入排序的效率就非常高,排序结果如下
这样操作,让我们用尽可能少的操作,使数组整体的有序程度得到了显著提高,这样操作过后,我们可以进一步缩小分组跨度,重复上述工 作。把跨度缩小为原先的一半,就是跨度为1,进行重新分组,在本例中再次分组的话也就是跨度为1,直接进行插入排序
这就是希尔排序,是希尔(Donald Shell) 于1959年提出的一种排序算法。上面示例中所使用的分组跨度(3,1),被称为希尔排序的增 量,增量的选择可以有很多种。我们在示例中所用的逐步折半的增量 方法,是Donald Shell在发明希尔排序时提出的一种朴素方法,被称 为希尔增量。
希尔排序的代码实现
public static void shellSort(int [] array) {
int d = array.length; //俩元素之间的距离
//折半,直到增量为1
while (d > 1) {
d = d >> 1;
for (int x = 0; x < d; x++) {
for (int i = x + d; i < array.length; i = i + d) {
int t = array[i];
int j;
for (j = i - d; (j >= 0) && (array[j] > t); j = j - d) {
array[j + d] = array[j];
}
array[j + d] = t; //由于for循环之后还减少了d所以这里加回来
}
}
}
}
public static void main(String[] args) {
int [] array = {3, 4, 2, 6, 5, 8};
shellSort(array);
System.out.println(Arrays.toString(array));
}
算法分析
- 最佳情况:T(n) = O(nlog2 n)
- 最坏情况:T(n) = O(nlog2 n)
- 平均情况:T(n) =O(nlog2n)
下篇预告: 图解十大排序篇四 归并排序