希爾排序:將無序數組分割為若干個子序列,子序列不是逐段分割的,而是相隔特定的增量的子序列,對各個子序列進行插入排序;然后再選擇一個更小的增量,再將數組分割為多個子序列進行排序......最后選擇增量為1,即使用直接插入排序,使最終數組成為有序。
增量的選擇:在每趟的排序過程都有一個增量,至少滿足一個規則 增量關系 d[1] > d[2] > d[3] >..> d[t] = 1 (t趟排序);根據增量序列的選取其時間復雜度也會有變化,這個不少論文進行了研究,在此處就不再深究;本文采用首選增量為n/2,以此遞推,每次增量為原先的1/2,直到增量為1;
下圖詳細講解了一次希爾排序的過程:
希爾排序,也稱遞減增量排序算法,是插入排序的一種更高效的改進版本。但希爾排序是非穩定排序算法。
希爾排序是基于插入排序的以下兩點性質而提出改進方法的:
- 插入排序在對幾乎已經排好序的數據操作時,效率高,即可以達到線性排序的效率;
- 但插入排序一般來說是低效的,因為插入排序每次只能將數據移動一位;
希爾排序的基本思想是:先將整個待排序的記錄序列分割成為若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行依次直接插入排序。
希爾排序算法的步驟:
- 選擇一個增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;
- 按增量序列個數 k,對序列進行 k 趟排序;
- 每趟排序,根據對應的增量 ti,將待排序列分割成若干長度為 m 的子序列,分別對各子表進行直接插入排序。僅增量因子為 1 時,整個序列作為一個表來處理,表長度即為整個序列的長度。
let arr = [65, 27, 59, 64, 58];
function shellSort(arr) {
var len = arr.length,
temp,
gap = 1;
while(gap < len/3) { //動態定義間隔序列
gap =gap*3+1;
console.log('定義間隔為:'+gap);
}
for (gap; gap > 0; gap = Math.floor(gap/3)) {
console.log('間隔為'+gap+'排序前:'+arr);
for (var i = gap; i < len; i++) {
temp = arr[i];
for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) {
arr[j+gap] = arr[j];
console.log('內部排序中!!調整:'+arr);
}
arr[j+gap] = temp;
console.log('需在'+(j+gap)+'位置插入'+temp+'后:'+arr);
}
console.log('排序后:'+arr);
console.log('-------------------');
}
console.log('最終結果:'+arr);
return arr;
}
shellSort(arr);
/**
定義間隔為:4
間隔為4排序前:65,27,59,64,58
內部排序中!!調整:65,27,59,64,65
需在0位置插入58后:58,27,59,64,65
排序后:58,27,59,64,65
-------------------
間隔為1排序前:58,27,59,64,65
內部排序中!!調整:58,58,59,64,65
需在0位置插入27后:27,58,59,64,65
需在2位置插入59后:27,58,59,64,65
需在3位置插入64后:27,58,59,64,65
需在4位置插入65后:27,58,59,64,65
排序后:27,58,59,64,65
-------------------
最終結果:27,58,59,64,65 */