經典排序演算法——快速排序及其優化
快速排序
快速排序的思想:通過一趟排序將資料分割成獨立的兩部分,其中一部分資料都比另一部分的所有資料都要小,然後再按照此方法對這兩部分資料分別進行快速排序,可以遞迴的進行。
時間複雜度:
- 好的情況(無序的):O(nlog2n)
- 壞的情況(有序的):O(n^2)
讓我們先通過一個例子來了解一下:
12 5 4 25 10 15
首先:我們選擇 12 為基準,比 12 小的放左邊。
5 4 10 12 25 15
同樣,用快速排序對 12 的前半部分進行排序:
4 5 10 12 25 15
此時,前半部分排序完畢,後半部分一樣用快速排序:
4 5 10 12 15 25
我們可以用遞迴的方法來求解。
下面我們換個例子來深入的理解快速排序演算法。
23 4 34 54 65 76 22 3 56 13 35 28 32 43 5
如下圖所示,為第一趟的快速排序。
此時,23 的前半部分都比 23 小,23 的後半部分都比 23 大。
我們可以對它的前半部分和後半部分分別進行快速排序,直到排序結束。
下面我們用 java 來實現快速排序演算法。
public static void quickSort(int[] array){ Quick(array,0,array.length -1); }
public static void Quick(int[] array,int start,int end){
int par = partion(array,start,end);
if(par > start + 1){
Quick(array,start,par-1);//對前半段進行快速排序
}
if(par < end-1){
Quick(array,par+1,end); //對後半段進行快速排序。
}
}
下面這個函式是返回基準位置的。即上面的例子中第一趟快速排序後 23 的位置。
public static int partion(int[] array,int start,int end){ int tmp = array[start]; while(start < end){ while(start < end && array[end] >= tmp){ --end; } if(start >= end){ break; }else{ array[start] = array[end]; } while(start < end && array[start] <= tmp){ ++start; } if(start >= end){ break; }else{ array[end] = array[start]; } } array[start] = tmp; return start; }
這是我們用遞迴來解決它,其實還有另外一種辦法,我們可以利用棧來解決這個問題。
還是上面的例子,讓我們來分析一下。
23 4 34 54 65 76 22 3 56 13 35 28 32 43 5
首先:我們來給來個快速排序,將它分成兩部分。
5 4 13 23 22 23 76 65 56 54 35 28 32 43 34
然後:和前面一樣,我們分別對左邊和右邊進行快速排序,但不同的是,這次我們要把下標 start 和 end 存入棧中,然後將右邊的下標 start 和 end 也存入棧中。
如圖
接著我們從棧裡取出,使 low 和 high 分別指向 start 和 end ,然後進行快速排序。
依次類推,我們一邊向棧裡取出元素,一邊向棧裡儲存元素,直到棧為空,表示我們的排序結束。
下面我們用 java 實現一下這個非遞迴的。
public static void QuickSort(int[] array){
int[] stack = new int[array.length];
int top = 0;
int low = 0;
int high = array.length -1;
int par = partion(array,low,high);
//入棧
if(par > low+1){
stack[top++] = low;
stack[top++] = par-1;
}
if(par < high-1){
stack[top++] = par+1;
stack[top++] = high;
}
//出棧
while(top > 0){
high = stack[--top];
low = stack[--top];
par = partion(array,low,high);
if(par > low+1){
stack[top++] = low;
stack[top++] = par-1;
}
if(par < high-1){
stack[top++] = par+1;
stack[top++] = high;
}
}
快速排序的優化
快速排序有以下優化方案
- 當待排序陣列當中資料比較少的時候,用直接插入法。
- 聚集相同元素法。
- 隨機選取基準法。
當資料比較少時,採用直接插入法排序
當資料比較少時,採用直接插入法排序比較高效。
所以我們只需要在快速排序的方法上增加一個判斷語句即可
以下為用 java 實現
public static void Quick1(int[] array,int start,int end){
//當資料少於 100 時用直接插入法排序即可
if((end - start + 1) < 100){
insertSort(array,start,end);
return;
}
int par = partion(array,start,end);
if(par > start + 1){
Quick1(array,start,par-1);
}
if(par < end-1){
Quick1(array,par+1,end);
}
}
聚集相同元素法
簡單來說就是找和基準相同的元素,這樣子可以減少遞迴的次數。
下面是把和基準相同的元素聚集到一起。
這裡附上程式碼
public static int[] focus(int[] array,int start,int end,int par,int left,int right){
//聚集和基準相同的元素
//左邊找
int parleft = par-1;
int parright = par + 1;
for(int i = par-1;i >= start;i--){
if(array[i] == array[par]){
if(i != parleft){
swap(array,i,parleft);
parleft--;
}else{
parleft--;
}
}
}
left = parleft;
//右邊找
for(int j = par+1;j <= end;j++){
if(array[j] == array[par]){
if(j != parright){
swap(array,j,parright);
parright++;
}else{
parright++;
}
}
}
right = parright;
int[] brray = new int[2];
brray[0] =left;
brray[1] = right;
return brray;
}
然後我們對於基準左邊和基準右邊分別進行排序,和優化前不同的是我們不用再比較和基準相同的元素了。
對於左邊,我們令 low = 0,high = pl-1。
對於右邊,我們令 low = pr-1, high = 長度-1。
public static void Quick2(int[] array,int start,int end){
int par = partion(array,start,end);
int left = par-1;
int right = par+1;
int[] b = focus(array,start,end,par,left,right);
left = brrar[0];
right = brrar[1];
if(par > start + 1){
Quick2(array,start,left);
}
if(par < end-1){
Quick2(array,right,end);
}
}
隨機選取基準法。
在資料已經有效的情況下,快速排序時間複雜度太高,為了解決這個問題,課一隨機選取基準來提高效率。
public static void Quick3(int[] array,int start,int end){
int par = partion(array,start,end);
//假設已經有序,就會提高效率
swap(array, start, (int)(Math.random()*10%(end-start))+start);
if(par > start + 1){
Quick(array,start,par-1);
}
if(par < end-1){
Quick(array,par+1,end);
}
}
相關推薦
經典排序演算法——快速排序及其優化
快速排序快速排序的思想:通過一趟排序將資料分割成獨立的兩部分,其中一部分資料都比另一部分的所有資料都要小,然後再按照此方法對這兩部分資料分別進行快速排序,可以遞迴的進行。時間複雜度:好的情況(無序的):O(nlog2n)壞的情況(有序的):O(n^2) 快速排序法不穩定。讓我
經典排序演算法——快速排序、歸併排序、堆排序
之前兩篇關於排序演算法的綜述以及平方階複雜度的3種具體型別的排序演算法,這一篇將具體介紹其中平均時間複雜度在平方階O(nlog2n)O(nlog_2n)O(nlog2n)的三個排序演算法,以及各種演算法的程式碼實現(親測正確)。 快速排序 快速排序是由東尼·霍
歸併排序演算法詳解及其優化
歸併排序演算法: 思想:分治法 每個遞迴過程涉及三個步驟 第一, 分解: 把待排序的 n 個元素的序列分解成兩個子序列, 每個子序列包括 n/2 個元素. 第二, 治理: 對每個子序列分別呼叫歸併排序__MergeSort, 進行遞迴操作 第三
經典排序演算法-快速排序(挖坑法、前後指標法)、基數排序
快速排序在實際應用中是比較表現好的排序演算法。快速排序我用兩種方法實現它。 第一種為方法,形象的稱為:挖坑法 基本思路:1、尋找pos位,然後將其分為兩段陣列,然後對這兩段陣列遞迴排序;
用JavaScript實現十大經典排序演算法--快速排序
快速排序,這也是在實際中最常用的一種排序演算法,速度快,效率高。就像名字一樣,快速排序是最優秀的一種排序演算法。 1)演算法原理 快速排序的基本思想:通過一趟排序將待排記錄分
經典排序演算法--快速排序
快速排序原理 快速排序是基於“分治法”原理實現,所謂分治法就是不斷的將原陣列序列按照一定規律進行拆分,拆分後各自實現排序直到拆分到序列只剩下一個關鍵字為止。快速排序首先選取一個關鍵字為標誌位(關鍵字的選取影響排序效率),然後將序列中小於標誌位的關鍵字移動至標誌位左側,大於標誌位的關鍵字移動至右側。一趟比較
java排序演算法—快速排序
快速排序 快速排序的思想方法: 1.先從數列中取出一個數作為基準數,記為x。 2.分割槽過程,將不小於x的數全放到它的右邊,不大於x的數全放到它的左邊。(這樣key的位置左邊的沒有大於key的,右邊的沒有小於key的,只需對左右區間排序即可)。 3.再對左右區間重複第二步,直到各區間
小甲魚 排序演算法 快速排序
小甲魚 排序演算法 快速排序 #include <stdio.h> //交換 void swap(int k[], int low, int high) { int temp; temp = k[low]; k[low] = k[high]; k[h
排序演算法之快速排序(關鍵詞:資料結構/演算法/排序演算法/快速排序)
快速排序 實現 def partition(nums, left, right): middle = (left+right) // 2 pivot = nums[middle] swap(nums, middle, right) # 現在主元 pivot 等於 num
最常用的排序演算法——快速排序
最常用的排序演算法,當然是快速排序演算法了,下面給出可以直接執行的快速排序演算法思想和程式碼: 思想: ①一般設定第一個數為基準數; ②先從右往左找一個小於基準數的數,在從左往右找一個比基準數大的數,然後交換他們; 繼續,直到兩邊探測變數“相遇”; ③交
排序演算法---快速排序,隨機快速排序和雙路快排(python版)
[原文連結](https://blog.csdn.net/m0_37519490/article/details/80648011) 1、什麼是快速排序演算法? 快速排序是由東尼·霍爾所發展的一種排序演算法,速度快,效率高,也是實際中最常用的一種演算法
[排序演算法]--快速排序的Java實現
快速排序 所謂快速排序:基於分治的思想,是氣泡排序的改進型。首先在陣列中選擇一個基準點並把基準點放於序列的開頭(該基準點的選取可能影響快速排序的效率,關於基準點的選擇方法後面再講解),然後分別從陣列的兩端掃描陣列,設兩個指示標誌(lo指向起始位置,hi指
[演算法學習筆記]又一個採用分治法的排序演算法----快速排序演算法
快速排序演算法 快速排序演算法是當前在實際排序應用中最好的選擇,雖然排序演算法最壞情況下的時間複雜度為O(n^2), 但是可以通過隨機化的方式避免最壞情況的發生, 而快速演算法的平均複雜度為O(n lgn), 而且隱含的常數因子非常小, 因此效率十分高.
PHP實現排序演算法----快速排序(Quick Sort)、快排
基本思想: 快速排序(Quicksort)是對氣泡排序的一種改進。他的基本思想是:通過一趟排序將待排記錄分割成獨立的兩部分,其中一部分的關鍵字均比另一部分記錄的關鍵字小,則可分別對這兩部分記錄繼續進行快速排序,整個排序過程可以遞迴進行,以達到整個序列有序的目的
排序演算法---快速排序c++實現
#include<iostream> using namespace std; void quicksort(int *list, int s, int t) { if(s < t) { int i = s, j = t; int piv
常用排序演算法——快速排序法
快速排序法是一種高效的排序法,演算法的最終效能取決於選取的中間值,直接實現的快速排序法如下: #include <iostream> #include <algorithm> static int partition( int* array, in
Java-時間複雜度為O(nlogn)的排序演算法(快速排序, 歸併排序, 堆排序, 希爾排序)
/** 包含多種靜態排序方法 * Created by Andre on 2016/6/27. */ public class Sorter { /** * 快速排序 * 遞迴形式 * 第一個記錄為樞軸 * 不穩定
排序演算法---快速排序
快速排序是對氣泡排序的改進,通過一趟排序將要排序的資料分割成獨立的兩個部分,其中一部分的所有資料比另一個部分的所有資料要小,再按照這種方法遞迴進行,使得整個資料變成有序序列。
排序演算法----快速排序
排序演算法的思路是通過一趟排序將陣列分為兩部分,一部分比另一部分都要小,以此遞迴即可得到最終的排序。複雜度nlogn void Qsort(int a[], int low, int high)//l
排序演算法——快速排序演算法
網際網路的大型公司還在火熱招聘中,參與了一次又一次的筆試,都不通過,我還是太菜!!! 作為程式設計人員,需要邁過去“資料結構與演算法”這個坎,畢竟,筆試不會真的很虧,加油吧,少些水,多點實操。 一、快速排序演算法思想: 從一組資料中找出一個基準值,一般是選擇中間值作為基