快速排序 (Quick Sort)(Java实现)
快速排序(Quicksort)是對冒泡排序的一種改進,借用了分治的思想,由C. A. R. Hoare在1962年提出。
1、基本思想
快速排序的基本思想:挖坑填數+分治法。
首先選一個軸值(pivot,也有叫基準的),通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續(xù)進行排序,以達到整個序列有序。
2、算法描述
快速排序使用分治策略來把一個序列(list)分為兩個子序列(sub-lists)。步驟為:
遞歸到最底部時,數列的大小是零或一,也就是已經排序好了。這個算法一定會結束,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最后的位置去。
3、代碼實現
用偽代碼描述如下:
3.1 遞歸實現
/*** 快速排序(遞歸)** ①. 從數列中挑出一個元素,稱為"基準"(pivot)。* ②. 重新排序數列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準后面(相同的數可以到任一邊)。在這個分區(qū)結束之后,該基準就處于數列的中間位置。這個稱為分區(qū)(partition)操作。* ③. 遞歸地(recursively)把小于基準值元素的子數列和大于基準值元素的子數列排序。* @param arr 待排序數組* @param low 左邊界* @param high 右邊界*/ public static void quickSort(int[] arr, int low, int high){if(arr.length <= 0) return;if(low >= high) return;int left = low;int right = high;int temp = arr[left]; //挖坑1:保存基準的值while (left < right){while(left < right && arr[right] >= temp){ //坑2:從后向前找到比基準小的元素,插入到基準位置坑1中right--;}arr[left] = arr[right];while(left < right && arr[left] <= temp){ //坑3:從前往后找到比基準大的元素,放到剛才挖的坑2中left++;}arr[right] = arr[left];}arr[left] = temp; //基準值填補到坑3中,準備分治遞歸快排System.out.println("Sorting: " + Arrays.toString(arr));quickSort(arr, low, left-1);quickSort(arr, left+1, high); }上面是遞歸版的快速排序:通過把基準temp插入到合適的位置來實現分治,并遞歸地對分治后的兩個劃分繼續(xù)快排。那么非遞歸版的快排如何實現呢?
因為遞歸的本質是棧,所以我們非遞歸實現的過程中,可以借助棧來保存中間變量就可以實現非遞歸了。在這里中間變量也就是通過Pritation函數劃分區(qū)間之后分成左右兩部分的首尾指針,只需要保存這兩部分的首尾指針即可。
3.2 非遞歸實現
/*** 快速排序(非遞歸)** ①. 從數列中挑出一個元素,稱為"基準"(pivot)。* ②. 重新排序數列,所有比基準值小的元素擺放在基準前面,所有比基準值大的元素擺在基準后面(相同的數可以到任一邊)。在這個分區(qū)結束之后,該基準就處于數列的中間位置。這個稱為分區(qū)(partition)操作。* ③. 把分區(qū)之后兩個區(qū)間的邊界(low和high)壓入棧保存,并循環(huán)①、②步驟* @param arr 待排序數組*/ public static void quickSortByStack(int[] arr){if(arr.length <= 0) return;Stack<Integer> stack = new Stack<Integer>();//初始狀態(tài)的左右指針入棧stack.push(0);stack.push(arr.length - 1);while(!stack.isEmpty()){int high = stack.pop(); //出棧進行劃分int low = stack.pop();int pivotIdx = partition(arr, low, high);//保存中間變量if(pivotIdx > low) {stack.push(low);stack.push(pivotIdx - 1);}if(pivotIdx < high && pivotIdx >= 0){stack.push(pivotIdx + 1);stack.push(high);}} }private static int partition(int[] arr, int low, int high){if(arr.length <= 0) return -1;if(low >= high) return -1;int l = low;int r = high;int pivot = arr[l]; //挖坑1:保存基準的值while(l < r){while(l < r && arr[r] >= pivot){ //坑2:從后向前找到比基準小的元素,插入到基準位置坑1中r--;}arr[l] = arr[r];while(l < r && arr[l] <= pivot){ //坑3:從前往后找到比基準大的元素,放到剛才挖的坑2中l++;}arr[r] = arr[l];}arr[l] = pivot; //基準值填補到坑3中,準備分治遞歸快排return l; }快速排序是通常被認為在同數量級(O(nlog2n))的排序方法中平均性能最好的。但若初始序列按關鍵碼有序或基本有序時,快排序反而蛻化為冒泡排序。為改進之,通常以“三者取中法”來選取基準記錄,即將排序區(qū)間的兩個端點與中點三個記錄關鍵碼居中的調整為支點記錄。快速排序是一個不穩(wěn)定的排序方法。
以下是快速排序算法復雜度:
| O(nlog?n) | O(nlog?n) | O(n2) | O(1)(原地分區(qū)遞歸版) |
快速排序排序效率非常高。 雖然它運行最糟糕時將達到O(n2)的時間復雜度, 但通常平均來看, 它的時間復雜為O(nlogn), 比同樣為O(nlogn)時間復雜度的歸并排序還要快. 快速排序似乎更偏愛亂序的數列, 越是亂序的數列, 它相比其他排序而言, 相對效率更高.
Tips: 同選擇排序相似, 快速排序每次交換的元素都有可能不是相鄰的, 因此它有可能打破原來值為相同的元素之間的順序. 因此, 快速排序并不穩(wěn)定.
4、拓展
https://github.com/iTimeTraveler/SortAlgorithms#六快速排序quick-sort
https://blog.csdn.net/shujuelin/article/details/82423852
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的快速排序 (Quick Sort)(Java实现)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 你这样写英硕论文肯定不及格你这样写英硕论
- 下一篇: java美元兑换,(Java实现) 美元