【演算法】排序04——程式碼簡約而不簡單的希爾排序(含程式碼實現)
1、希爾排序的效能簡介
希爾排序是插入排序的改進型,也因此,它的空間複雜度是O(1)。不過有趣的是,希爾排序的平均時間複雜度計與其增量有關,算起來較為複雜,dalao們的研究認為是O[n^(1.3 ~ 2)]之間。
其實相比於快排、歸併、堆排這些平均之間複雜度為O [ nlog(n) ]的線性對數階排序,希爾排序並不佔優勢(因為希排有亞二次時間界),但作為第一批突破第二次時間屏障的演算法之一的存在,我jio得還是要重溫一下經典(其實是面試愛考ORZ)。
2、本文中的一些定義
2.1——有序區與無序區
在本文中,對於一個任意一個無序的的序列:
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ]
我們把這個序列從邏輯上分為有序區和無序區,並預設在開始排序前,第一個元素為有序區,其餘為無序區。
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] (綠色為有序區,紅色為無序區)
在我們對其逐漸有序化的時候,依次從無序區中取出其第一個元素並插入有序區:
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] (有序區會增加,無序區會減少,同時無序區第一個元素前的元素必然在有序區)
2.2——按增量(gap)劃分多個序列
一個序列可以按增量(gap)在邏輯上劃分為gap個序列(關於的gap的取值,第一次取序列長度一半,之後再取用gap前要除2):
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] gap = 9/2 = 4 ,即在邏輯上分成4組小序列,同一小序列內的、邏輯上相鄰的元素,在序列中的小標差為gap:
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] 比如紅色小序列應該是[ 5, 7, 3 ],它們在原序列中的小標為0、4、8,相差為gap
3、希爾排序的流程
第一步,在邏輯上按gap將序列劃分為gap個小序列。(第一次時取增量(gap)為序列長度的一半)
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ]
第二步,一個指標從序列的無序區(由各個小序列的無序區組成)由左向右遍歷,遍歷到的元素,將其插入對應小序列的有序區”
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] 指標最開始指向序列無序區第一個即7,7在第一個小序列裡,把它插入第一個小序列的有序區,
如, [ 5, 6, 9, 8, 7, 4, 1, 2, 3 ] 指標+1指向無序區新的第一個元素4,4在第二個小序列裡, 把它插入第二個小序列的有序區,
如, [ 5, 4, 9, 8, 7, 6, 1, 2, 3 ] 注意,這裡是插入到第二個小序列的有序區,所以4、6換位,然後指標+1。。。。操作同上
第三步,gap/=2後若小於1就結束了,否則回撥第一步。
4、程式碼
1 import java.util.Arrays; 2 public class Main { 3 public static void shellSort(int[] arr) { 4 int temp; 5 //控制增量(gap),增量將不斷/2直到小於1。(序列會在邏輯上按gap劃分為gap個小序列) 6 for (int gap = arr.length/2; gap >0; gap/=2) { 7 //遍歷無序區(最開始>=gap的下標都屬於無序區) 8 //變數p_in_unorder始終指向當前序列的無序區的第一個元素的下標 9 for (int p_in_unorder = gap; p_in_unorder < arr.length; p_in_unorder++) { 10 /* 11 *p_in_order是小序列有序區內的下標指標 12 *p_in_unorder - gap 是當前小序列有序區的最後一個 13 *把當前無序區第一個元素插入對應小序列有序區 14 */ 15 for (int p_in_order = p_in_unorder-gap ; p_in_order >= 0 ; p_in_order-=gap) { 16 if(arr[p_in_order]>arr[p_in_order+gap]){ 17 temp = arr[p_in_order]; 18 arr[p_in_order] = arr[p_in_order+gap]; 19 arr[p_in_order+gap] = temp; 20 } 21 } 22 } 23 } 24 } 25 26 public static void main(String[] args) { 27 int[] arr = new int[]{5,6,9,8,7,4,1,2,3}; 28 shellSort(arr); 29 System.out.println(Arrays.toString(arr)); 30 } 31 }
最後,如果小夥伴覺得這篇博文對你有幫助的話,就點個推