快速排序 递归版本和非递归方法 c代码
快速排序平均時間是T(n) =knln(n),其中n為待排序序列中記錄個數,k為某個常數。通常,快速排序被認為是,在所有同數量級(O(nlogn))的排序方法中,其平均性能最好,但是,若初始記錄按關鍵字有序或者基本有序,快速排序將蛻變為冒泡排序,其時間復雜度為O(n^2)。
快速排序聽起來挺簡單,實現代碼看起來也很簡單。但簡單只是相對而言,如果不理解其思路的話,現場寫代碼還是有一定難度,因此需要理解其思想再去寫代碼。
快速排序答題思路是先將排序序列按照樞軸值分成兩個子集,左子集中的元素都小于樞軸值,右子集的元素都大于樞軸值,這里的關鍵是找到樞軸值的位置。然后使用遞歸對子集在進行同樣的分割操作,遞歸終點就是子集中元素個數為一。樞軸值可以從序列中隨機去一個出來,根據經驗,“三者取中”的法則可最大改善快速排序在最壞情況下的性能。“三者取中”即在 arr[ i ],? arr[ j ],? arr[(i + j) / 2]取中值。
舉個例子,序列array,長度為N,取樞軸值pivotKey = array[n/2], pivotLoc = n/2,設置兩個指針low 和 high,從low開始,找到大于pivotKey的值,假設在i位置(i <? pivotLoc && array[i] > pivotKey),交換pivotLoc和i的值,這時候pivotLoc位置就變為i,這時候從high往前搜索,找到小于pivotLoc的值,然后和pivotLoc交換。如果low < high的話重復上述過程,直到low == high,這時候low == high == pivotLoc。得到兩個子集array[0 ~ pivotLoc] 和 array[ pivotLoc +1, high],遞歸調用即可,直到子集中元素個數為1返回。
c代碼如下:
//兩個數值互換 void swap(int *a, int *b) {if (a == b)return;*a = *a ^ *b;*b = *a ^ *b;*a = *a ^ *b; }void quickSort(int *arr, int low, int high) {int pivotKey, pivotLoc;int left = low;int right = high;if (low < high){//保存樞軸點和樞軸值pivotLoc = (low + high) / 2;pivotKey = arr[pivotLoc];while (low < high){while (low < pivotLoc && arr[low] <= pivotKey)low++;if (low < pivotLoc){swap(arr+low, arr+pivotLoc);pivotLoc = low;}while(high > pivotLoc && arr[high] >= pivotKey)high--;if (high > pivotLoc){swap(arr+high, arr+pivotLoc);pivotLoc = high; }}quickSort (arr, left, pivotLoc);quickSort (arr, pivotLoc + 1, right);}return; }非遞歸版本,通常使用的是遞歸版本的快速排序,但是有時候也會遇到要求實現非遞歸版本的快速排序。之前聽誰說過,遞歸的問題都可以使用棧來實現。快速排序也是一樣。我們分析遞歸版本的快速排序,快速排序一遍后得到左右兩個子集,這時候分別對兩個左右子集遞歸調用快速排序。復又得到左右子集。知道子集中邊界元素為1為止。這個過程,可以用棧來模擬,比如,一次排序后,左右子集的邊界入棧。如果棧不為空,取出棧的子集邊界,調用快速排序。復又得到左右子集邊界,進棧。重復此過程,直到棧空。整個過程和樹的寬度優先遍歷類似。代碼如下:
//快速排序,返回樞軸點 int quickSort(int *nums, int begin, int end) {int pivot, i = begin, j = end;pivot = nums[i];while (i < j){while (j > i && nums[j] >= pivot)j--;if (j > i)swap (nums+j, nums+i);elsebreak;while (i < j && nums[i] <= pivot)i++;if (i < j)swap (nums+j, nums+i);elsebreak; }return i; }void main() {int top = 0, low = 0, high, pivot, stack[100] = {0};int nums[] = {10,3,1,8,4,5,2,9,8,6,5};int size = sizeof(nums)/sizeof(int);high = size - 1;//第一次快速排序pivot = quickSort (nums, 0, size - 1);//子集邊界入棧if (pivot - 1 > low){stack[top++] = pivot - 1;stack[top++] = low;}if (pivot + 1 < high){stack[top++] = high;stack[top++] = pivot + 1;}//從棧中取出邊界繼續進行快速排序while (top > 0){low = stack[--top];high = stack[--top];//復又得到左右邊界,繼續入棧pivot = quickSort (nums, low, high);if (pivot - 1 > low){stack[top++] = pivot - 1;stack[top++] = low;}if (pivot + 1 < high){stack[top++] = high;stack[top++] = pivot + 1;}} }?
參考資料:
1.?數據結構?: C語言版/ 嚴蔚敏,吳偉民編著
=============================================================================================
Linux應用程序、內核、驅動、后臺開發交流討論群(745510310),感興趣的同學可以加群討論、交流、資料查找等,前進的道路上,你不是一個人奧^_^。
?
總結
以上是生活随笔為你收集整理的快速排序 递归版本和非递归方法 c代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摇钱花查征信吗
- 下一篇: leetcode 4. 寻找两个有序数组