前言
今天做排序的時候,把希爾排序寫錯了。寫一篇希爾排序原理懲罰自己。
1 原理概述
希爾排序是插入排序的一種改進算法。它先將一個大的待排序數列分成多個小的分組,并分別對這些小的分組使用插入排序算法。經過多輪分組與組內排序,逐步合并小的分組,最終將分組重新合并成一個有序序列。
那么怎么將一開始分出的這些小分組合并成一個完整的數列呢?規則是什么呢?客官請往下看。
2 算法描述
由于個人描述能力欠佳,為避免說的太抽象,這里我們結合實例進行介紹。
這里有一個需要進行排序的數列 arr = [88, 10, 47, 41, 39, 15, 0, 53, 6, 75],下面我們要對它執行希爾排序。
希爾排序在對數列進行分組時,用到一個概念,我們之為“增量”。增量即為分組的步長。這里使用的是希爾增量。
希爾排序開始前,按照實際需要設定一個初始增量(我們這里設定 fraction = arr.length / 2,即增量為 5)。這樣就可以將數列分組,并對每個分組執行插入排序。所有分組都執行完插入排序,視為第一輪排序完成。
讓我們看看這一輪排序發生了什么:
// 排序前
[88, 10, 47, 41, 39, 15, 0, 53, 6, 75]
88 ***************** 15
**** 10 ***************** 0
******** 47 *************** 53
************* 41 *************** 6
**************** 39 ************** 75
// 排序后
[15, 0, 47, 6, 39, 88, 10, 53, 41, 75]
15 ************** 88
**** 0 **************** 10
******** 47 **************** 53
********** 6 **************** 41
************* 39 ***************** 75
在第1輪排序中,數列被分為5個分組,經過本輪排序,此時每個分組內部均為有序。
此時,將增量減小(fraction = 5 / 2,即步長為 2),重新劃分數列,并對每個新的分組執行插入排序。
我們看一下這一輪排序發生了什么:
// 排序前
[88, 10, 47, 41, 39, 15, 0, 53, 6, 75]
88 **** 47 **** 39 ***** 0 **** 6
*** 10 **** 41 ***** 15 *** 53 *** 75
// 排序后
[0, 10, 6, 15, 39, 41, 47, 53, 88, 75]
0 **** 6 **** 39 **** 47 **** 88
** 10 *** 15 **** 41 **** 53 **** 75
在第2輪排序中,數列被分為2個分組,經過本輪排序,此時每個分組內部均為有序。
此時,再次減小增量(fraction = 2 / 2 ,即步長為1),重新劃分數列,并對每個新的分組執行插入排序。
我們看一下這一輪排序發生了什么:
// 排序前
[0, 10, 6, 15, 39, 41, 47, 53, 88, 75]
// 排序后
[0, 6, 10, 15, 39, 41, 47, 53, 75, 88]
在第3輪排序中,數列只有一個分組,經過本輪排序,整個數列內的元素為遞增排列,希爾排序算法執行完畢。
3 性能分析
3.1 穩定性
由于插入排序是將待排序元素順次插入新的有序序列中,不會改變原數列中相同關鍵字元素的相對位置,所以我們說插入排序是穩定的。
希爾排序算法在進行每一輪排序時,只能保證組內元素有序,但在調整組內元素的時候,可能令分在兩個組中且具有相同關鍵字的元素交換位置。例如:
// 對如下數組使用希爾排序,增量為希爾增量
// 第一輪排序結果如下:
// 排序前
[1, 49, 33, 49, 5, 62]
1 ******** 49
** 49 ******** 5
****** 33 ******** 62
// 排序后
[1, 5, 33, 49, 49, 62]
1 ******** 49
** 5 ******** 49
****** 33 ******** 62
在這個例子中,經過第一輪排序關鍵字為49的元素,在原數列中的相對位置已經發生了改變。
綜上可知,希爾排序是不穩定的排序算法。
3.2 時間復雜度
希爾排序的時間復雜度是不確定的,設置不同的增量規則,會對希爾排序的性能造成很大影響。例如:在希爾增量下,希爾排序的時間復雜度為O(n2);在Hibbard增量下,希爾排序的時間復雜度為O(n(3/2));希爾排序時間復雜度下限為 n*log2n。
快速排序算法( O(n(log2n)) )在大規模數據情況下,通常比希爾排序表現更好,所以當數據量極大時,可以優先考慮使用快速排序代替希爾排序。但是,在確定增量的情況下,希爾排序在時間復雜度的表現通常比較穩定,極端情況的上下浮動小,因此普適性更強,可以作為排序算法的首選,在發現表現欠佳時,再考慮用其他算法替換。
4 javascript 代碼實現
var arr = (function(len){
if(!len) return [0];
var arr = [];
for(var i = len; i > 0; i--) arr.push(Math.floor( Math.random() * 100 ))
return arr
})(10);
console.log("original arr : ",arr)
for(var fraction = Math.floor(arr.length / 2); fraction >= 1; fraction = Math.floor(fraction / 2)) {
for(var i = fraction; i < arr.length; i++) {
for(var j = i - fraction;j >= 0 && arr[j] > arr[j + fraction]; j -= fraction) {
var temp = arr[j];
arr[j] = arr[j + fraction];
arr[j + fraction] = temp;
}
}
}
console.log("result : ",arr)
參考資料
[1] [百度百科] 希爾排序
[2] [Foliciatarier的博客] 希爾排序增量序列簡介