(1)希爾排序(shell sort)這個排序方法又稱為縮小增量排序,是2023年d·l·shell提出來的。該方法的基本思想是:設待排序元素序列有n個元素,首先取乙個整數increment(小於n)作為間隔將全部元素分為increment個子序列,所有距離為increment的元素放在同乙個子串行中,在每乙個子串行中分別實行直接插入排序。然後縮小間隔increment,重複上述子串行劃分和排序工作。直到最後取increment=1,將所有元素放在同乙個子串行中排序為止。
(2)由於開始時,increment的取值較大,每個子串行中的元素較少,排序速度較快,到排序後期increment取值逐漸變小,子串行中元素個數逐漸增多,但由於前面工作的基礎,大多數元素已經基本有序,所以排序速度仍然很快。
(3)希爾排序舉例:
1>下面給出乙個資料列:
2>第一趟取increment的方法是:n/3向下取整+1=3(關於increment的取法之後會有介紹)。將整個資料列劃分為間隔為3的3個子序列,然後對每乙個子串行執行直接插入排序,相當於對整個序列執行了部分排序調整。**如下:
3>第二趟將間隔increment= increment/3向下取整+1=2,將整個元素序列劃分為2個間隔為2的子串行,分別進行排序。**如下:
4>第3趟把間隔縮小為increment= increment/3向下取整+1=1,當增量為1的時候,實際上就是把整個數列作為乙個子串行進行插入排序,**如下:
5>直到increment=1時,就是對整個數列做最後一次調整,因為前面的序列調整已經使得整個序列部分有序,所以最後一次調整也變得十分輕鬆,這也是希爾排序效能優越的體現。
(4)希爾排序演算法的**實現(c++)
//函式功能,希爾排序演算法對數字遞增排序
//函式引數,數列起點,數列終點
void shell_sort(const
int start, const
int end) ;
do while (j >= start && numbers[j] > temp);
numbers[j + increment] = temp; //插入元素}}
} while (increment > 1);
}
上面的函式的第乙個do……while控制increment每次的縮小,其內部便是直接插入排序演算法的使用,與直接插入排序演算法稍有不同的一點是:其j每次的變化量是increment而不是1。
(5)關於希爾排序increment(增量)的取法。
增量increment的取法有各種方案。最初shell提出取increment=n/2向下取整,increment=increment/2向下取整,直到increment=1。但由於直到最後一步,在奇數字置的元素才會與偶數字置的元素進行比較,這樣使用這個序列的效率會很低。後來knuth提出取increment=n/3向下取整+1.還有人提出都取奇數為好,也有人提出increment互質為好。應用不同的序列會使希爾排序演算法的效能有很大的差異。
(6)希爾排序應該注意的問題
從上面**希爾排序的過程可以看到,相等的排序碼25在排序前後的順序發生了顛倒,所以希爾排序是一種不穩定的排序演算法。
(1)對希爾排序的時間複雜度分析很困難,在特定情況下可以準確的估算排序碼的比較次數和元素移動的次數,但要想弄清楚排序碼比較次數和元素移動次數與增量選擇之間的依賴關係,並給出完整的數學分析,還沒有人能夠做到。
(2)這裡我們把3種常用的插入排序做乙個程式測試,通過每種演算法測試所執行的時間,來定性的認識希爾排序的效能優劣。測試的思路是通過生成1000個1——1000之間的隨機數,令三種排序演算法分別對其進行排序,輸出排序所花費的時間。
(3)測試的程式原始碼(c++)
/*
* 插入排序演算法
*/#include
#include
#include
#include
using
namespace
std;
//vectornumbers;
//vectornumbers;
//vectornumbers;
vector
numbers;
//函式功能,直接插入演算法對數字排序
//函式引數,數列起點,數列終點
void dinsert_sort(const
int start, const
int end) while (j >= start && numbers[j] > temp);
numbers[j + 1] = temp; //插入元素}}
}//函式功能,折半插入演算法對數字排序
//函式引數,數列起點,數列終點
void binsert_sort(const
int start, const
int end)
else
}for (int k = i - 1; k >= low; --k)
numbers[low] = temp; //插入元素
}}//函式功能,希爾排序演算法對數字遞增排序
//函式引數,數列起點,數列終點
void shell_sort(const
int start, const
int end) ;
do while (j >= start && numbers[j] > temp);
numbers[j + increment] = temp; //插入元素}}
} while (increment > 1);
}//函式功能,隨機產生amount個start——end內的隨機數並存入指定容器
//函式引數,隨機數範圍起點,隨機數範圍終點,隨機數生成數量
void producerandomnumbers(const
int start, const
int end, const
int amount)
}int main()
system("pause");
return
0;}
(4)有關測試結果
直接插入排序:
折半插入排序:
希爾排序:
當然這裡沒有讓其對同一組資料進行測試,會存在一定的誤差,但是通過對其多次測試,3中演算法的平均優劣程度還是比較明顯的。
參考
(二)排序 折半插入,希爾,與氣泡排序
折半插入 include includeint a 16 輸出已排序陣列 void print printf n 折半插入排序公升序排列 void binaryinsertsortup else 確定好位置後,將位置之後的資料後移,插入待排序資料 for j i 1 j high j a j 1 x...
插入排序(直接插入排序 折半插入排序和希爾排序)
所謂插入排序就是將乙個待排序的記錄,按其關鍵字大小插入到前面已經排好序的子串行中,直到全部記錄插入完成。1.直接插入排序 假設在排序過程中,待排序表l 1 n 在某次排序過程中的某一時刻狀態如下 為了實現將元素l i 插入到已有序列的子串行l 1 i 1 中,需要執行以下操作 1 查詢l i 在l ...
內部排序系列 之 插入排序與shell 希爾 排序
嗯嗯,這是本人第二次更新部落格 距離第一次已經好久好久啦 這一系列的部落格是本人早就想要寫的,不過內容太多又恐不慎之處會誤人子弟.遂醞釀了很長一段時間,終於在最近將這篇部落格完成了.當然,由於本人的知識和技術實在有限,所以文章中不可避免的會有些錯誤,希望各位看官能不吝批評指出.文章中的解析等都是上課...