手写快速排序
前言
快速排序是一種很重要的排序算法,我花了不少時間去理解并總結它,希望可以通過圖文的方式讓你快速理解快速排序,并能手擼一個快排。
快速排序簡介
快速排序是一種很不錯的排序算法,算法復雜度為n*logn。快排使用了分而治之的思想,每次排序是都找到一個基準(我們學習時經常使用第一個作為基準),然后把小于基準的元素放到基準元素的左邊,大于基準的元素放到基準元素的右邊,這樣一次排序下來,基準元素左邊都是小于(等于)基準的數,基準右邊的元素都是大于(等于)基準的元素了。快速排序關鍵點就是找到這樣一個基準并將其放到恰到的位置。
算法思路
定義一個快速排序函數,arr是要排序的數組,l指向要排序的數組最左邊的元素,r指向要排序的數組最右邊的元素。
public static void quick_sort(int arr[],int l,int r){if(l >= r) return;//p為快速排序返回的基準的位置int p = partition2(arr,l,r);//對基準左邊的數進行快排quick_sort(arr,l,p-1);//對基準右邊的數進行快排quick_sort(arr,p+1,r);}那么現在關鍵就是這么實現這個partition2函數
假設現在有一個數組arr[]:
我們每次都取第一個元素為基準元素,定義i指向基準的下一個元素位置,j指向最后一個元素的位置:
i 從左向右掃描,如果arr[i] <= v , i++
j從右向左掃描,如果 arr[j] > v ,j–
直到i指向一個大于v的元素,j指向一個小于j的元素,且 這個過程中 i <= j
此時i左邊(除基準元素)都是小于v的,j右邊都是大于v的,現在只需要交換arr[i]與arr[j]的位置,就可以把小于v的放左邊,大于v的放右邊,然后i++,j–
繼續比較,此時arr[i] = 4 < 5,i++ ,arr[j] > 5 j–
到這里 i > j 了,退出循環,最后把基準v與arr[j]交換位置,即把v放到了小于v的元素的最后一個,此時一次快速排序就完成了。
代碼實現
//快速排序,另一種從前后掃描的public static int partition2(int arr[],int l,int r){//基準元素設為第一個int v = arr[l];//i指向基準的下一個元素,j指向最后一個元素int i = l+1,j = r;while(true){while(i <= r && arr[i] < v) i++;while(j > l && arr[j] > v) j--;//循環終止條件if(i > j) break;//交換arr[i]與arr[j]int t = arr[i];arr[i] = arr[j];arr[j] = t;i++;j--;}//將基準元素與arr[j]交換int t = arr[l];arr[l] = arr[j];arr[j] = t;//返回基準元素所在位置return j;}快速排序的幾個問題
1、對于幾乎有序的數組,快速排序返回的基準的位置都在第一個或很靠前的位置,使得對數組的切分不夠平均,可能使得快速排序的時間復雜度退到o(n^2) , 對于這種情況,可以在排序時選取數組中的一個隨機位置的數作為基準數。
2、對于數組中的元素有很多相等元素時,也會導致快排對數組的切分不平衡,此時快排的時間復雜度也可能退到o(n^2) , 對于這種情況,可以使用三路快速排序,把小于基準v的放左邊,等于v的放中間,大于v的放右邊,就避免了左右不平衡的問題。
3、在進行快排時候,當數比較少的時候,使用插入排序代替快排可提高算法效率。
三路快速排序
三路快速排序針對數組中有很多相等元素時照樣能有很不錯的效率,其主要思想就是將數組中的數分成三個部分:小于基準v的放左邊,等于v的放中間,大于v的放右邊。
代碼
總結
- 上一篇: 【弄nèng - Activiti6】A
- 下一篇: oracle 10231事件,Oracl