梳排序

梳排序（Comb sort）是一種由弗拉基米爾・多博舍維奇（Wlodzimierz Dobosiewicz）於 1980 年所發明的不穩定排序演算法，並由史蒂芬・萊西（Stephen Lacey）和理查德・博克斯（Richard Box）於 1991 年四月號的中推廣。梳排序是改良自泡沫排序和快速排序，其要旨在於消除「烏龜」，亦即在陣列尾部的小數值，這些數值是造成泡沫排序緩慢的主因。相對地，「兔子」，亦即在陣列前端的大數值，不影響泡沫排序的效能。

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

遞減率

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

亦有人提議用作遞減率，同時增加換算表協助於每一迴圈開始時計算新間距。

因為程式語言中乘法比除法快，故會取遞減率倒數與間距相乘，

變異形式

2.1 梳排序 - 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)。

2.2 混合梳排序和其他排序演算法

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

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

虛擬碼

梳排序程式（以 array 作輸入）

gap = array 的長度 // 設定開始時的間距

當 gap > 1 或 swaps = 1 時執行迴圈 // 代表未完成排序

gap = 取「gap 除以遞減率」的整數值 // 更新間距

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

// 把輸入陣列「梳」一次

i = 0 到 (array 的長度 - 1 - gap) 來執行迴圈 // 從首到尾掃描一次；因為陣列元素的編號從 0 開始，所以最後一個元素編號為長度 - 1

如果 arrayi > arrayi+gap

把 arrayi 和 arrayi+gap 的數值交換

swaps = 1 // 曾作交換，故此陣列未必排序好

如果結束

迴圈結束

迴圈結束

程式結束

實作範例

4.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 arri + gap) {

				temp = arri;

				arri = arri + gap;

				arri + gap = temp;

				swapped = 1;

			}

	}

}

4.2 C++

template // 整數或浮點數皆可使用，若要使用物件（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 arri + gap) {swap (arri, arri + gap);

				swapped = 1;

			}

	}

}

4.3 Java

public static > 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 0) {

E t = inputi;

inputi = inputi + gap;

inputi + gap = t;

swapped = true;

}

i++;

}

}

}

4.4 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 thisi + gap) {

				temp = thisi;

				thisi = thisi + gap;

				thisi + gap = temp;

				swapped = 1;

			}

	}

	return this;

};

4.5 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 $arr$i + $gap) {swap ($arr$i, $arr$i + $gap);

				$swapped = 1;

			}

	}

}

4.6 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

4.7 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 Ai>Ai+gap

				Ai,Ai+gap = Ai+gap,Ai

				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

上例中，共作了六次交換以完成排序。