排序算法——希尔排序(缩小增量排序)
1.希爾排序思想:
希爾排序就是把數據分成若干份子序列,從第一個元素開始,和每間隔為n的元素分成一個子序列,對每一份子序列實行直接插入排序,然后合并成一個新序列,繼續對新序列以間隔m分成若干份,繼續重復步驟,直至一個元素一份,對所有元素實行直接插入排序。如下步驟(注意,實際增量并不是按照-1變化的,我們這里只是為了觀看過程,以達到理解希爾排序思想的目的)
第一次分解排序:
我們畫圖舉例,比如我們一開始有下列數據,且第一次以間隔4(即增量為4)分成若干子序列:
如上圖,間隔為4,分若干個子序列,顏色相同的為一個子序列,那么上圖就會分成下面的四個子序列:
子序列1:
子序列2:
子序列3:
子序列4:
對每個子序列進行直接插入排序,使得每個子序列都有序,然后再組合成新的數組如下:
第二次分解排序:
繼續對上面數組分成子序列,比如第二次以間隔3(即增量為3)分成若干子序列,顏色相同的為一個子序列:
對每個子序列直接插入排序然后組合成新序列為(由于巧合,分解后的每個子序列都有序,所以組合后和第一步組合后的數組一樣):
第三次分解排序:
把第二次分解排序后的數組分成子序列,比如第三次以間隔2(即增量為2)分成若干子序列,那么分解后的子序列為:
如上圖,紅色為一個子序列,紫色為一個子序列,對這兩個子序列分別進行直接插入排序,然后數組變成如下圖:
第四分解排序
我們增量為1,那么第一個和第二個…一直到最后一個,整個數組是一個子序列,對其進行直接插入排序。此時數組已經接近有序了,所以此時插入排序會更接近O(n)。
總結:不難看出,思想很巧妙,而且一開始的時候,交換次數會多,到后面越來越有序,調用直接插入排序時,時間復雜度也越來越接近O(n)。其實我個人覺得希爾排序和歸并排序有異曲同工之妙。
我覺得,歸并排序和希爾排序的區別就在于一開始的時候。
歸并排序一開始是一個元素為一個序列,然后倆倆合并成一個有序的子序列,再倆倆子序列合并,最后生成一個有序的子序列。
希爾排序是一開始依靠增量將數組分成若干個子序列,然后將子序列排序合并(注意是在原數組上操作,實際是對下標的掌控,進而對值的掌控,在下面代碼中體現出來),增量變小,繼續分,繼續排,增量越來越小,子序列越來越長,到最后只剩一個子序列(即增量為1),簡單使用直接插入排序就完成了。
2.希爾排序的增量選擇
增量increment的取法有各種方案。最初shell提出取increment=n/2向下取整,increment=increment/2向下取整,直到increment=1。但由于直到最后一步,在奇數位置的元素才會與偶數位置的元素進行比較,這樣使用這個序列的效率會很低。后來Knuth提出取increment=n/3向下取整+1。還有人提出都取奇數為好,也有人提出increment互質為好。應用不同的序列會使希爾排序算法的性能有很大的差異。(此段話摘自博客為此處)
3.希爾排序代碼
void ShowArr(int* arr, int len) {for (int i = 0; i < len; ++i){printf("%d ", arr[i]);}printf("\n"); }void ShellSort(int* arr,int start,int end) {int increment = (end - start + 1);//初始化劃分增量int flg = 1;//注意:此變量對希爾排序無意義,我們這里只是為了統計數組第幾次排序while(increment != 1)//劃分增量==1是最后一次排序,過后數組有序,結束排序{increment = increment / 3 + 1;//劃分增量每次都用上次的劃分增量除以三向上取整for (int i = start + increment; i <= end; i++)//從start+increment開始,后面就是各子序列的非有序數據{int tmp = arr[i];//保存子序列未排序的部分的最左邊的元素while (i - increment >= 0 && arr[i - increment] > tmp)//找非有序數據在有序數據應該放置的位置{arr[i] = arr[i - increment];i = i - increment;//間隔increment的數據才為同一個子序列的數據,所以找子序列元素需要跳著找 }arr[i] = tmp;}printf("第%d次排序、增量為%d后數組:\n", flg++,increment);ShowArr(arr, end+1);} }int main() {int arr[] = { 23,34,13,25,67,74,65,42,31,13,79 };ShellSort(arr, 0, sizeof(arr) / sizeof(arr[0])-1);return 0; }運行結果:
觀察每一次排序后數組的元素變化,和我們最開始討論希爾排序思想過程一樣。
總結
以上是生活随笔為你收集整理的排序算法——希尔排序(缩小增量排序)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 排序算法——冒泡排序、选择排序、直接插入
- 下一篇: 内联函数和宏定义