排序詳解(希爾,快排,歸併等)

2021-08-15 10:50:06 字數 4176 閱讀 3823

今天集中把幾種排序的方法列一下,當然最出名的希爾,快排,歸併和其優化當然也是滿載

說到希爾排序的話,不得不先提到的就是插入排序了,希爾排序就是對直接插入排序的一種優化,下面就是直接插入排序的思想

直接插入排序

這就是直接插入排序的**,思想很簡單,**也很簡單

為什麼希爾排序比直接插入排序更加優化呢?當需要排序的陣列過長的時候,有可能出現,插入資料的時候需要把資料插入到陣列頭的位置,那麼陣列中需要移動的資料就太多了,效率很低,但是當陣列趨於有序的時候,直接插入排序的效率是很高的,所以希爾排序可以理解為直接插入排序的預排序,讓陣列更趨於有序,希爾排序的最後一趟排序就是直接插入排序

希爾排序

將乙個陣列進行分組(就是隔幾個元素分為一組)如下圖

分組之後,對每一組都進行插入排序,執行完一次所有的分組的插入排序之後算作完成一趟排序,然後減少gap的值,直到最後一次gap的值會變為1,成為直接插入排序

下面是**

void shellsort(int *a,size_t size)

a[end + gap] = tmp;}}

}

每次對gap的值進行gap=gap/3+1,為啥?因為比較優,具體應該就是數學問題了,我就不太清楚了。。。。

接下來是選擇排序,選擇選擇,就是每一次選出最大(小)值,然後交換到最高(低)的位置,優化!一次不僅可以選出最小的值,還可以選出最大的,同時選出,同時交換,可以提高效率

void selectsort(int *a,size_t size )

if ( a[max]< a[j])

}swap(a[i], a[min]);

swap(a[size - 1 - i], a[max]);}}

思想啥的就不貼了,畢竟是比較簡單和基礎的排序了

堆排序

接下來就是堆排序了!什麼是堆,這裡我就進行簡單的介紹了,堆的本質是乙個陣列,將這個陣列看成乙個二叉樹,很抽象,來個圖

順序把陣列弄成二叉樹,大堆(每個父親節點都比孩子節點的值要大),小堆(每個父親節點都比孩子節點的值要小,上圖就是乙個小堆),所謂的堆排序就是把待排序的陣列先建堆

每一次交換之後將調整的範圍縮小乙個,這樣就能保證,每次交換到最後的數都是大數,並到了自己應該到的位置上去,建堆的過程用到向下調整,,每一次交換之後也要向下調整,堆是一種資料結構,這裡就不詳解了,之後會整理出堆來,這裡介紹堆排序的思想和**

void adjustdown(int *a, size_t size, int root)

if (a[child]>a[root])

else

}}void heapsort(int *a, size_t size)

for (int i = size - 1; i >= 0; --i)

}

接下來就是快排了!!這個被譽為十大演算法的傢伙!!

快速排序

快排的思想是拆分遞迴,直到遞迴到最深層(就乙個元素)

但是不夠優化,當每次取的key值恰好比較接近最大值或者最小值的時候,分界遞迴的時候就會出現分布不均勻,導致效率低下,當劃分成兩邊相等的時候自然比較好,所以加上這個部分會比較好

int getmidindex(int *a, int left, int right)

else if (a[mid] < a[right])

else

return right;

}else

else if (a[mid] < a[left])

else

return left;}}

三數取中法,**已經更新過了,所以上邊的快排已經是用三數取中優化過的

當快排遞迴到比較深層的時候,被分成小部分的區間內已經趨於有序了,那麼採用直接插入排序就可以有效的提高效率!!具體做法就是在quicksort中的if部分修改,改掉遞迴結束條件,然後加上直接插入排序的**就好了

這個不能算是優化,思想有些不同,這次是從同一邊走採用cur和prev兩個引數,外層的遞迴還是不變的,只是一次排序不同了

最後key值還是會跑到大概中間的位置,和他自己應該在的地方比較接近

最後乙個排序就是歸併排序啦!

歸併排序

歸併排序一上來就將陣列分割成兩部分,然後不停的分割,直到乙個元素不能再分位置,然後開始合併相鄰的兩個元素,合併之後當然是有序的,有序之後就可以回到上一層,然後不斷的進行合併,最後整個陣列都有序啦,也就是說要想合併,兩個部分都必須是有序的才行。

就是類似這樣的

思想還是不太難理解的

實現這樣的思想需要開闢輔助空間,因為當兩部分有序的陣列合併之後還要是有序的才行,需要乙個同等大小的陣列暫存一下資料

void mergeselection(int *a, int *tmp, int begin1, int end1, int begin2, int end2)

else

tmp[index++] = a[begin2++];

}while (begin1 <= end1)

while (begin2 <= end2)

}void mergesort(int *a ,int *tmp,int left,int right)

}

tmp是我在測試用例中就開闢好的陣列空間,直接作為引數傳進去

常用排序演算法 希爾,歸併,快排

public static comparable void shellsort t arr while h 1 h h 3 public class 歸併排序 對兩個有序序列進行合併 param arr param low param mid param high param temp privat...

排序演算法 快排,歸併

從陣列中隨機選乙個數,比這個數大的放右邊,比這個數小的放左邊。快排中的乙個細節 如果乙個數等於p的時候,既可以在左邊又可以在右邊。這麼做是為了避免如果陣列中所有的數都一樣,則會造成資料的不平衡。快排的目的是能夠使得左邊和右邊的數都差不多,這樣的話時間複雜度就不會退化到o n 2 而是o n logn...

排序演算法 歸併 快排

歸併排序的思想是分治法,如果想要將乙個陣列排序,那麼將這個陣列分為左區間和右區間,左區間一定是小於右區間的,再將左區間繼續劃分,右區間也繼續劃分。最後將排好序的陣列全都歸併起來,這樣聽起來像是從上向下劃分,其實歸併排序主要是是從下向上,合併的過程。先將單個元素的陣列歸併為兩個元素的有序陣列 再將包含...