**梳排序（Comb sort）**是一種由Wlodzimierz Dobosiewicz（英语：）於1980年所發明的不穩定排序算法，並由Stephen Lacey（英语：）和Richard Box（英语：）於1991年四月號的Byte雜誌（英语：）中推廣。梳排序是改良自泡沫排序和快速排序，其要旨在於消除*烏龜*，亦即在陣列尾部的小數值，這些數值是造成泡沫排序緩慢的主因。相對地，*兔子*，亦即在陣列前端的大數值，不影響泡沫排序的效能。

在泡沫排序中，只比較陣列中相鄰的二項，即比較的二項的*間距（Gap）*是1，梳排序提出此間距其實可大於1，改自插入排序的希爾排序同樣提出相同觀點。梳排序中，開始時的間距設定為陣列長度，並在迴圈中以固定比率遞減，通常*遞減率*設定為1.3。在一次迴圈中，梳排序如同泡沫排序一樣把陣列從首到尾掃描一次，比較及交換兩項，不同的是兩項的間距不固定於1。如果間距遞減至1，梳排序假定輸入陣列大致排序好，並以泡沫排序作最後檢查及修正。

遞減率
---

遞減率的設定影響著梳排序的效率，原作者以隨機數作實驗，得到最有效遞減率為1.3的。如果此比率太小，則導致一迴圈中有過多的比較，如果比率太大，則未能有效消除陣列中的烏龜。

亦有人提議用{\displaystyle 1/\left(1-{\frac {1}{e^{\varphi }}}\right)\approx 1.247330950103979}作遞減率，同時增加換算表協助於每一迴圈開始時計算新間距。

因為程式語言中乘法比除法快，故會取遞減率倒數與間距相乘，{\displaystyle {\frac {1}{1.247330950103979}}=0.801711847137793\approx 0.8}

變異形式
----

### 梳排序-11

設定遞減率為1.3時，最後只會有三種不同的間距組合：(9, 6, 4, 3, 2, 1)、(10, 7, 5, 3, 2, 1)、或 (11, 8, 6, 4, 3, 2, 1)。實驗證明，如果間距變成9或10時一律改作11，則對效率有明顯改善，原因是如果間距曾經是9或10，則到間距變成1時，數值通常不是遞增序列，故此要進行幾次泡沫排序迴圈修正。加入此指定間距的變異形式稱為*梳排序-11(Combsort11)*。

### 混合梳排序和其他排序算法

如同快速排序和合併排序，梳排序的效率在開始時最佳，接近結束時最差。如果間距變得太小時(例如小於10)，改用插入排序或希爾排序等算法，可提昇整體效能。

此方法最大好處是不需要檢查是否進行過交換程序以將排序迴圈提早結束。

虛擬碼
---

```

梳排序程序（以array作輸入）
    gap = array的長度 //設定開始時的間距
      

    當gap > 1或swaps = 1時執行迴圈 //代表未完成排序
        gap = 取「gap除以遞減率」的整數值 //更新間距
          

        swaps = 0 //用以檢查陣列是否已在遞增形式，只限gap=1時有效
          

        //把輸入陣列「梳」一次
        i = 0 到 (array的長度 - 1 - gap)來執行迴圈 //從首到尾掃描一次；因為陣列元素的編號從0開始，所以最後一個元素編號為長度-1
            如果array[i] > array[i+gap]
                把array[i]和array[i+gap]的數值交換
                swaps = 1 //曾作交換，故此陣列未必排序好
            如果結束
        迴圈結束
    迴圈結束
程序結束
```

實作範例
----

### C語言

```
void comb\_sort(int arr[], int len) {
 double shrink\_factor = 0.8;
 int gap = len, swapped = 1, i;
 int temp;
 while (gap > 1 || swapped) {
 if (gap > 1)
 gap \*= shrink\_factor;
 swapped = 0;
 for (i = 0; gap + i < len; i++)
 if (arr[i] > arr[i + gap]) {
 temp = arr[i];
 arr[i] = arr[i + gap];
 arr[i + gap] = temp;
 swapped = 1;
 }
 }
}

```

### C++

```
template<typename T> //整數或浮點數皆可使用，若要使用物件（class）時必須設定大於（>）的運算子功能
void comb\_sort(T arr[], int len) {
 double shrink\_factor = 0.8;
 int gap = len, swapped = 1, i;
 while (gap > 1 || swapped) {
 if (gap > 1)
 gap = (int) ((double) gap \* shrink\_factor);
 swapped = 0;
 for (i = 0; gap + i < len; i++)
 if (arr[i] > arr[i + gap]) {
 swap(arr[i], arr[i + gap]);
 swapped = 1;
 }
 }
}

```

### Java

```
public static <E extends Comparable<? super E>> void sort(E[] input) {
 int gap = input.length;
 boolean swapped = true;
 while (gap > 1 || swapped) {
 if (gap > 1) {
 gap = (int) (gap \* 0.8);
 }
 int i = 0;
 swapped = false;
 while (i + gap < input.length) {
 if (input[i].compareTo(input[i + gap]) > 0) {
 E t = input[i];
 input[i] = input[i + gap];
 input[i + gap] = t;
 swapped = true;
 }
 i++;
 }
 }
}

```

### JavaScript

```
Array.prototype.comb\_sort = function() {
 var shrink\_factor = 0.8;
 var gap = this.length, swapped = 1, i;
 var temp;
 while (gap > 1 || swapped) {
 if (gap > 1)
 gap = Math.floor(gap \* shrink\_factor);
 swapped = 0;
 for (i = 0; gap + i < this.length; i++)
 if (this[i] > this[i + gap]) {
 temp = this[i];
 this[i] = this[i + gap];
 this[i + gap] = temp;
 swapped = 1;
 }
 }
 return this;
};

```

### PHP

```
function swap(&$x, &$y) {
	$t = $x;
	$x = $y;
	$y = $t;
}
function comb\_sort(&$arr) {//php的陣列視為基本型別，所以必須用傳參考才能修改原陣列
	$shrink\_factor = 0.8;
	$gap = count($arr);
	$swapped = 1;
	while ($gap > 1 || $swapped) {
		if ($gap > 1)
			$gap = floor($gap \* $shrink\_factor);
		$swapped = 0;
		for ($i = 0; $gap + $i < count($arr); $i++)
			if ($arr[$i] > $arr[$i + $gap]) {
				swap($arr[$i], $arr[$i + $gap]);
				$swapped = 1;
			}
	}
}

```

### Go

```
func comb\_sort(data sort.Interface) {
 n := data.Len()
 shrinkFactor := 0.8
 gap := n
 swapped := true

 for gap > 1 || swapped {
 if gap > 1 {
 gap = int(float64(gap) \* shrinkFactor)
 }

 // 冒泡排序
 swapped = false
 for i := 0; i < n - gap; i++ {
 if data.Less(i + gap, i) {
 data.Swap(i + gap, i)
 swapped = true
 }
 }
 }
}

```

### Julia (程式語言)

```
# Julia Sample : CombSort

function CombSort(A)
 gap,swapped = length(A),1

 while (gap>1) || (swapped==1)
 gap = floor(Int,gap/1.25)
 swapped=0
 for i=1:(length(A)-gap)
 if A[i]>A[i+gap]
 A[i],A[i+gap] = A[i+gap],A[i]
 swapped=1
 end
 end
 end
 return A
end

# Main Code
A = [16,586,1,31,354,43,3]
println(A) # Original Array
println(CombSort(A)) # Comb Sort Array

```

動作原理
----

假設輸入為

8 4 3 7 6 5 2 1
目標為將之變成遞增排序。因為輸入長度=8，開始時設定間距為8/1.3≒6，則比較8和2、4和1，並作交換兩次。

**8** 4 3 7 6 5 **2** 1
2 **4** 3 7 6 5 8 **1**
2 1 3 7 6 5 8 4
第二次迴圈，更新間距為6/1.3≒4。比較2和6、1和5，直至7和4，此迴圈中只須交換一次。

2 1 3 **7** 6 5 8 **4**
2 1 3 4 6 5 8 7
接下來的每次迴圈，間距依次遞減為3 → 2 → 1，

間距=3時，不須交換

2 1 3 4 6 5 8 7
間距=2時，不須交換

2 1 3 4 6 5 8 7
間距h=1時，交換三次

**2** **1** 3 4 6 5 8 7
1 2 3 4 **6** **5** 8 7
1 2 3 4 5 6 **8** **7**
1 2 3 4 5 6 7 8
上例中，共作了六次交換以完成排序。

參考文獻
----

1. 1 2  Brejová, Bronislava. "Analyzing variants of Shellsort"

參看
--

* 泡沫排序，梳排序的基本，較慢的算法。
* 雞尾酒排序，或雙向泡沫排序，一樣解決了泡沫排序中的烏龜問題。

外部連結
----

|  |  |
| --- | --- |
|  | 維基教科書中的相關電子：**Sorting/Comb sort** |

* .NET Implementation of comb sort and several other algorithms （页面存档备份，存于）
* Combsort - Who ever knew that bubblesort could be so good?

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
算法 |
| --- |
|  |
| 排序 | 

|  |  |
| --- | --- |
| 比较排序 | 
* 冒泡排序
* 选择排序
* 插入排序
* 希尔排序
* 快速排序
* 归并排序
* 堆排序
* 鸡尾酒排序
* 梳排序
* 侏儒排序
* 图书馆排序
* 内省排序
* 奇偶排序

 |
|  |
| 线性时间排序 | 
* 鸽巢排序
* 基数排序
* 計數排序
* 桶排序

 |
|  |
| 并行排序 | 
* 排序网络（英语：）
* Batcher归并网络

 |
|  |
| 不实用的 | 
* Bogo排序
* 臭皮匠排序

 |
|  |
| 图 | 
* 拓撲排序

 |

 |
|  |
| 搜索 | 

|  |  |
| --- | --- |
| 列表 | 
* 线性搜索
* 二分搜索
* 插值搜尋

 |
|  |
| 树・图 | 
* 广度优先搜索
	+ 最良優先搜索（英语：）
	+ 均一开销搜索
	+ A\*
* 深度优先搜索
	+ 迭代深化深度优先搜索
	+ 深度限制搜索（日语：）
	+ 双向搜索
* 分枝限定法（英语：）

 |
|  |
| 字符串 | 
* KMP算法
* 博耶-穆尔字符串搜索算法
* AC自动机算法
* 拉宾-卡普算法
* bitap算法

 |

 |
|  |
| 最短路问题 | 
* 戴克斯特拉算法
* 贝尔曼-福特算法
* A\*搜尋演算法
* Floyd-Warshall算法

 |
|  |
| 最小生成树 | 
* 普林姆算法
* 克鲁斯克尔演算法

 |
|  |
| 最大流最小割 | 
* 福特-富尔克森算法
* 埃德蒙兹-卡普算法
* 迪尼茨算法

 |
|  |
| 线性规划 | 
* 单纯形法
* 卡马卡尔算法（英语：）

 |
|  |
| 順序統計量 | 
* 选择算法
* 中位数的中位数（英语：）

 |
|  |
| 種類 | 
* 精确算法
* 近似算法
* 随机化算法

 |
|  |
| 其他 | 
* 分治法
* 动态规划
* 贪心算法

 |
|  |
| **Category:算法** |

 |

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
排序算法 |
| --- |
|  |
| 理论 | 
* 計算複雜性理論
* 大O符号
* 全序关系
* 数据结构术语列表
* 原地算法
* 稳定性
* 比较排序
* 自适应排序（英语：）
* 排序网络（英语：）
* 整数排序（英语：）
* X+Y排序（英语：）
* 量子排序（英语：）

 |
|  |
| 交换排序 | 
* 冒泡排序
* 鸡尾酒排序
* 奇偶排序
* 梳排序
* 侏儒排序
* 快速排序
* 慢速排序
* 臭皮匠排序
* Bogo排序

 |
|  |
| 选择排序 | 
* 选择排序
* 堆排序
* 平滑排序（英语：）
* 笛卡尔树排序（英语：）
* 锦标赛排序（英语：）
* 圈排序（英语：）
* 弱堆排序（英语：）

 |
|  |
| 插入排序 | 
* 插入排序
* 希尔排序
* 伸展排序
* 二叉查找树排序
* 图书馆排序
* 耐心排序

 |
|  |
| 归并排序 | 
* 归并排序
* 梯级归并排序（英语：）
* 振荡归并排序（英语：）
* 多相归并排序（英语：）

 |
|  |
| 分布排序 | 
* 美国旗帜排序（英语：）
* 珠排序
* 桶排序
* 爆炸排序（英语：）
* 计数排序
* 比較計數排序
* 插值排序
* 鸽巢排序
* 相邻图排序（英语：）
* 基数排序
* 闪电排序（英语：）

 |
|  |
| 并发排序 | 
* 双调排序器（英语：）
* Batcher归并网络
* 两两排序网络（英语：）

 |
|  |
| 混合排序 | 
* 塊排序（英语：）
* Tim排序
* 内省排序
* Spread排序（英语：）
* 归并插入排序（英语：）

 |
|  |
| 其他 | 
* 拓撲排序
* 煎餅排序
* 意粉排序（英语：）

 |

 |