原文地址:Data Structure and Algorithms - Shell Sort
什么是希尔算法?
希尔排序是一种基于插入排序的高效的排序算法。如果较小的值在最右端,且必须移动到最左端,则这种算法避免了在插入排序情况下的最大位移(转换)
该算法对广泛分布的元素使用插入排序,首先对它们进行排序,然后对间距较小的元素进行排序。 该间隔称为间隔。 该间隔是根据努斯公式公式计算得出的:
该算法首先使用一个较大的间隔元素进行插入排序,然后使用一个较小的间隔元素做插入排序。该间隔称为interval<间隔/增量>(或gap,或increment,下文都把interval叫做<间隔/增量>) 该<间隔/增量>是根据努斯公式计算得出的:
h = h * 3 + 1
where −
h is interval with initial value 1
对于中等大小的数据集,此算法非常有效,因为该算法的平均复杂度和最坏情况的复杂度取决于间隔序列(间隔数组,gap array),最著名的是间隙序列(n),其中n是项数。 最坏的情况是空间复杂度为O(n)。
希尔排序是如何工作的?
让我们根据以下案例来思考希尔排序的工作原理。我们使用和先前示例相同的数组。为了让我们的示例更易于理解,我们采用4的<间隔/增量>。 我们采用步长为4的<间隔/增量>来创建一个虚拟子列表。这些值分别是{35,14},{33,19},{42,27}和{10,44}
我们比较每个子列表中的值,并在原始数组中交换它们(如果需要)。 完成此步骤后,新数组应如下所示:
然后,我们用步长为2的<间隔/增量>,来生成子列表,此<间隔/增量>生成两个子列表:{14,27,35,42},{19,10,33,44}
如果需要,我们将比较并交换原始数组中的值。完成这些步骤之后,该数组应该像下面这样:
最后,我们使用值步长为1的<间隔/增量>,来排序剩下的数组,希尔排序使用插入排序来排序这些数组 以下是分步描述:
我们看到它只需要四个交换就可以对数组的其余部分进行排序。
Algorithm
第1步-初始化h的值
第2步-将列表分为等间隔h的较小子列表
第3步-使用插入排序对这些子列表进行排序
第4步-重复直到对完整列表进行排序
非JS伪代码:
procedure shellSort()
A : array of items
/* calculate interval*/
while interval < A.length /3 do:
interval = interval * 3 + 1
end while
while interval > 0 do:
for outer = interval; outer < A.length; outer ++ do:
/* select value to be inserted */
valueToInsert = A[outer]
inner = outer;
/*shift element towards right*/
while inner > interval -1 && A[inner - interval] >= valueToInsert do:
A[inner] = A[inner - interval]
inner = inner - interval
end while
/* insert the number at hole position */
A[inner] = valueToInsert
end for
/* calculate interval*/
interval = (interval -1) /3;
end while
end procedure
Javscript:
function shell_sort(arr) {
for (let gap = arr.length >> 1; gap > 0; gap >>= 1) {
for (let i = gap; i < arr.length; i++) {
let temp = arr[i];
for (let j = i - gap; j >= 0 && arr[j] > temp; j -= gap) {
arr[j + gap] = arr[j];
}
arr[j + gap] = temp;
}
}
return arr;
};