七、希尔排序(Shell Sort)
1、概念
使用二分的思想,将排序序列分组,直到每组的元素数量是1为止。
交换式
:以分组元素数量为索引间距,依次比较每个分组的首元素和尾元素,若发现逆序,则交换元素顺序(在比较过程中,排好多个组的顺序)。最终将所有组的元素都比较一遍,实现最终的排序。
位移式
:以分组元素数量为索引间距,对每个分组进行直接插入排序(依次比较每个分组的首元素和尾元素,若发现逆序,则将首元素的值覆盖掉尾元素的值,比较完毕后,再将尾元素的值覆盖掉上次比较到逆序的元素索引的下一个索引间距的元素的值。最终将所有组的元素都比较一遍,实现最终的排序。)
希尔排序属于插入排序
的一种。
2、过程
- 三层嵌套循环。
- 最外层循环,用于二分排序序列,首次二分取排序序列长度的一半,之后每次取上次二分结果的一半。这也是索引间距的值。
- 中间层循环,用于确定每次排序时的起始位置和终止位置,从二分的结果为起始索引位置,到排序序列的长度前一位为止。
- 最内层循环,用于比较首尾元素的大小。
- 交换式:从起始索引位置减去索引间距开始,到每组的首个元素索引位置为止。每次比较首尾两个元素的值,发现逆序,则交换元素顺序。
- 位移式:从起始索引位置减去索引间距开始,用临时变量保存起始索引位置元素值和下次查找首元素索引位置,不断地向前比较元素值大小,直到该组的元素都比较完毕(索引位置不能越界),发现逆序,则将本次的首元素值覆盖掉尾元素值,最后再将临时变量,起始索引位置元素值,覆盖掉上次比较的首元素索引位置的下一个索引间距的元素值。
3、示例
交换式
/**
* 交换式-正序
*/
public void shellSort(int[] array) {
int temp;
for (int len = array.length, gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (array[j] > array[j + gap]) { // 比较首尾元素
temp = array[j];
array[j] = array[j + gap];
array[j + gap] = temp;
}
}
}
}
}
/**
* 交换式-倒序
*/
public void shellSort(int[] array) {
int temp;
for (int len = array.length, gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
for (int j = i - gap; j >= 0; j -= gap) {
if (array[j] < array[j + gap]) { // 倒序
temp = array[j];
array[j] = array[j + gap];
array[j + gap] = temp;
}
}
}
}
}
位移式
/**
* 位移式-正序
*/
public void shellSort(int[] array) {
for (int len = array.length, gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
int element = array[i];
int index = i - gap;
while (0 <= index && element < array[index]) { // 比较首尾元素
array[index + gap] = array[index]; // 元素值后移
index -= gap; // 索引前移
}
array[index + gap] = element;
}
}
}
/**
* 位移式-倒序
*/
public void shellSort(int[] array) {
for (int len = array.length, gap = len / 2; gap > 0; gap /= 2) {
for (int i = gap; i < len; i++) {
int element = array[i];
int index = i - gap;
while (0 <= index && element > array[index]) { // 倒序
array[index + gap] = array[index];
index -= gap;
}
array[index + gap] = element;
}
}
}
4、性能
- 时间复杂度:平均时间复杂度
O(nlog₂n)
,最坏时间复杂度O(n^k) 1 < k < 2
- 空间复杂度:
O(1)
- 稳定性:不稳定(a=b,排序前a在b的前面,排序后a不一定还在b的前面)