数据结构和算法-希尔排序(译文)

187 阅读3分钟

原文地址: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}

1.jpg

我们比较每个子列表中的值,并在原始数组中交换它们(如果需要)。 完成此步骤后,新数组应如下所示:

2.jpg

然后,我们用步长为2的<间隔/增量>,来生成子列表,此<间隔/增量>生成两个子列表:{14,27,35,42},{19,10,33,44}

3.jpg

如果需要,我们将比较并交换原始数组中的值。完成这些步骤之后,该数组应该像下面这样:

4.jpg

最后,我们使用值步长为1的<间隔/增量>,来排序剩下的数组,希尔排序使用插入排序来排序这些数组 以下是分步描述:

5.jpg

我们看到它只需要四个交换就可以对数组的其余部分进行排序。

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;
};