梳排序

Harshit Jindal 2023年10月12日
  1. 梳排序算法
  2. 梳排序示例
  3. 梳排序算法的实现
  4. 梳排序算法复杂度
梳排序

梳排序是一种简单的基于比较的排序算法。它是冒泡排序的改进形式。在冒泡排序中,相邻的元素在每一个段落/阶段进行比较,并逐一消除反转。另一方面,梳排序从使用大间隙开始,每次以 1.3 的收缩系数缩小间隙。梳排序只需一次交换就可以去除多个反转。它是基于杀乌龟的思想。海龟是指列表末尾的小元素,它降低了冒泡排序的效率,杀死海龟可以显著提高排序性能。

梳排序算法

假设我们有一个包含 n 元素的无序数组 A[]。我们取收缩因子为 1.3,因为经验上发现它能给出最好的结果。

  • 初始化变量 gap 为数组的大小,变量 swappedtrue
  • 将常量变量 SHRINK_FACTOR 声明为 1.3
  • gap 不是 1 或 swapped 设置为 true 时,执行以下操作。
    • 设置 swappedfalse
    • 设置 gap(int)gap/SHRINK_FACTOR
    • 对于 0n - gap 范围内的每个元素,执行以下操作 - 如果 A[i]>A[i+gap],则 swap(A[i], A[i+gap]),并将 swapped 设为 true

梳排序示例

假设我们有数组:(3, 5, 2, 8, 1, 7, 6, 4). 我们将使用梳排序算法对其进行排序。

初始化 gap=8 , swapped=trueSHRINK_FACTOR=1.3

  • 第一遍

gap=8/1.3=6,swapped=false

迭代 (3, 5, 2, 8, 1, 7, 6, 4) 动作
i = 0 (3, 5, 2, 8, 3, 7, 6, 4) 3<6,不交换
i = 1 (3, 4, 2, 8, 1, 7, 6, 5) 5>4, 交换
  • 第二遍

gap=6/1.3=4,swapped=false

迭代 (3, 4, 2, 8, 1, 7, 6, 5) 动作
i = 0 (1, 4, 2, 8, 3, 7, 6, 5) 3>1,交换
i = 1 (1, 4, 2, 8, 3, 7, 6, 5) 4<7,不交换
i = 2 (1, 4, 2, 8, 3, 7, 6, 5) 2<6,不交换
i = 3 (1, 4, 2, 5, 3, 7, 6, 8) 8>5, 交换
  • 第三遍

gap= 4/1.3 = 3,swapped=false

迭代 (1, 4, 2, 5, 3, 7, 6, 8) 动作
i = 0 (1, 4, 2, 5, 3, 7, 6, 8) 1<5,不交换
i = 1 (1, 3, 2, 5, 4, 7, 6, 8) 4>3,交换
i = 2 (1, 3, 2, 5, 4, 7, 6, 8) 2<7,不交换
i = 3 (1, 3, 2, 5, 4, 7, 6, 8) 5<6,不交换
i = 4 (1, 3, 2, 5, 4, 7, 6, 8) 4<8,不交换
  • 第四遍

gap=3/1.3=2,swapped=false

迭代 (1, 3, 2, 5, 4, 7, 6, 8) 动作
i = 0 (1, 3, 2, 5, 4, 7, 6, 8) 1<2,不交换
i = 1 (1, 3, 2, 5, 4, 7, 6, 8) 3<5,不交换
i = 2 (1, 3, 2, 5, 4, 7, 6, 8) 2<4,不交换
i = 3 (1, 3, 2, 5, 4, 7, 6, 8) 5<7,不交换
i = 4 (1, 3, 2, 5, 4, 7, 6, 8) 4<6,不交换
i = 5 (1, 3, 2, 5, 4, 7, 6, 8) 7<8,不交换
  • 第五遍

gap=2/1.3=1,swapped=false

迭代 (1, 3, 2, 5, 4, 7, 6, 8) 动作
i = 0 (1, 3, 2, 5, 4, 7, 6, 8) 1<3,不交换
i = 1 (1, 2, 3, 5, 4, 7, 6, 8) 3>2,交换
i = 2 (1, 2, 3, 5, 4, 7, 6, 8) 3<5,不交换
i = 3 (1, 2, 3, 4, 5, 7, 6, 8) 5>4, 交换
i = 4 (1, 2, 3, 4, 5, 7, 6, 8) 5<7,不交换
i = 5 (1, 2, 3, 5, 4, 6, 7, 8) 7>6, 交换
i = 6 (1, 2, 3, 4, 5, 6, 7, 8) 7<8,不交换

我们得到最终的排序数组为: (1, 2, 3, 4, 5, 6, 7, 8)

梳排序算法的实现

#include <iostream>
using namespace std;

int updateGap(int gap) {
  gap = (gap * 10) / 13;
  if (gap < 1)
    return 1;
  else
    return gap;
}

void combSort(int arr[], int n) {
  int gap = n;
  bool swapped = true;
  while (gap > 1 || swapped == true) {
    gap = updateGap(gap);
    swapped = false;
    for (int i = 0; i < (n - gap); i++) {
      int temp;
      if (arr[i] > arr[i + gap]) {
        temp = arr[i];
        arr[i] = arr[i + gap];
        arr[i + gap] = temp;
        swapped = true;
      }
    }
  }
}

int main() {
  int n = 6;
  int arr[6] = {5, 3, 4, 2, 1, 6};
  cout << "Input array: ";
  for (int i = 0; i < n; i++) {
    cout << arr[i] << " ";
  }
  cout << "\n";
  combSort(arr, n);
  cout << "Output array: ";
  for (int i = 0; i < n; i++) {
    cout << arr[i] << " ";
  }
  cout << "\n";
}

梳排序算法复杂度

时间复杂度

  • 平均情况

时间复杂度为 [O Theta]级:O(n2/2p) 其中 p 是增量的数量。

  • 最坏情况

最坏情况下的时间复杂度为 [BigO]:O(n2)。

  • 最佳情况

最好的情况发生在数组已经排序或接近排序的时候。最佳情况下的时间复杂度是 [Big Omega]:O(nlogn)。它比气泡排序的最佳情况时间复杂度有很大的改进。

空间复杂度

该算法的空间复杂度为 O(n),因为除了临时变量外,梳排序算法不需要额外的空间。

作者: Harshit Jindal
Harshit Jindal avatar Harshit Jindal avatar

Harshit Jindal has done his Bachelors in Computer Science Engineering(2021) from DTU. He has always been a problem solver and now turned that into his profession. Currently working at M365 Cloud Security team(Torus) on Cloud Security Services and Datacenter Buildout Automation.

LinkedIn

相关文章 - Sort Algorithm