1 基本介绍
1.1 概述
希尔排序是希尔(Donald Shell)于1959年提出的一种排序算法。希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序。希尔排序相比较与插入排序多加了一步就是确定步长。之前在插入排序的过程中,步长是固定的即为1,在希尔排序中的步长是不固定的,一开始步长是数组长度的一半,之后每次分组排序之后步长就再减半,直到步长到1为止,这时候排序就已经完成了。
插入排序的问题点:
插入排序的时候,我们会发现一个很不友好的事儿,如果已排序的分组元素为 {2,5,7,9,10},未排序的分组元素为{1,8},那么下一个待插入元素为1,我们需要拿着1从后往前,依次和10,9,7,5,2进行交换位置,才能完成真正的插入,每次交换只能和相邻的元素交换位置。那如果我们要提高效率,直观的想法就是一次交换,能把1放到更前面的位置,比如一次交换就能把1插到2和5之间,这样一次交换1就向前走了5个位置,可以减少交换的次数,这样的需求如何实现呢?
1.2 算法详解
希尔排序法基本思想:
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。
基本步骤:
希尔排序的基本步骤,在此我们选择增量 gap= length/2,缩小增量继续以 gap = gap/2 的方式,这种增量选择我们可以用一个序列来表示,{n/2,(n/2)/2…1},称为增量序列。希尔排序的增量序列的选择与证明是个数学难题,我们选择的这个增量序列是比较常用的,也是希尔建议的增量,称为希尔增量,但其实这个增量序列不是最优的。此处我们做示例使用希尔增量。
静图分析:
动画展示:
2 代码实现
2.1 代码实现
2.1.1 希尔排序-交换法
/**
* 希尔排序
*/
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
System.out.println("------------排序前------------");
System.out.println(Arrays.toString(arr));
shellSort2(arr);
System.out.println("------------排序后------------");
System.out.println(Arrays.toString(arr));
}
// 希尔排序-交换法
public static void shellSort(int[] arr) {
int temp = 0;
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
for (int i = gap; i < arr.length; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (arr[j] > arr[j + gap]) {
temp = arr[j];
arr[j] = arr[j + gap];
arr[j + gap] = temp;
}
}
}
}
}
}
2.1.1 希尔排序-插入法
/**
* 希尔排序
*/
public class ShellSort {
public static void main(String[] args) {
int[] arr = {8, 9, 1, 7, 2, 3, 5, 4, 6, 0};
System.out.println("------------排序前------------");
System.out.println(Arrays.toString(arr));
shellSort(arr);
System.out.println("------------排序后------------");
System.out.println(Arrays.toString(arr));
}
// 希尔排序-插入法(推荐)
public static void shellSort(int[] arr) {
// 增量 gap,并逐步的缩小增量
for (int gap = arr.length / 2; gap > 0; gap /= 2) {
// 从第 gap 个元素,逐个对其所在的组进行直接插入排序
for (int i = gap; i < arr.length; i++) {
int j = i;
int temp = arr[j];
if (arr[j] < arr[j - gap]) {
while (j - gap >= 0 && temp < arr[j - gap]){
// 移动
arr[j] = arr[j-gap];
j -= gap;
}
// 当退出 while 后,就给 temp 找到插入的位置
arr[j] = temp;
}
}
}
}
}
2.2 性能分析
时间复杂度
- 最优时间复杂度:根据步长序列的不同而不同
- 最坏时间复杂度:O(n^2)
- 稳定性:不稳定
希尔排序不像其他时间复杂度为O(N log2N)的排序算法那么快,但是比选择排序和插入排序这种时间复杂度为O(N2)的排序算法还是要快得多,而且非常容易实现。它在最坏情况下的执行效率和在平均情况下的执行效率相比不会降低多少,而快速排序除非采取特殊措施,否则在最坏情况下的执行效率变得非常差。
迄今为止,还无法从理论上精准地分析希尔排序的效率,有各种各样基于试验的评估,估计它的时间级介于O(N^3/2)和 与 O(N^7/6)之间。
我们可以认为希尔排序的平均时间复杂度为o(n^1.3)。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142560.html