演算法導論_第七章_快速排序
演算法導論_第七章_快速排序
快速排序的描述:
與歸併排序一樣,快速排序也使用了分治思想。
下面是對一個陣列進行快速排序的三部分治過程:
1.分解:陣列A[p,r]被劃分為兩個子陣列A[p,q-1]和A[q+1,r],使得A[p,q-1]中的每一個元素都小於等於A[q],而A[q]也小於等於A[q+1,r];
2.解決:通過遞迴呼叫快速排序,對子陣列進行排序。
3.合併:因為其是進行原址操作,所以其不需要合併
下面給出詳細程式碼,介紹其具體運算過程:
/*************************************************************************
> File Name: quicksort.cpp
> Author:chudongfang
> Mail:1149669942@qq.com
> Created Time: 2016年06月28日 星期二 21時11分41秒
************************************************************************/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int partition(int A[],int p,int r);
void quicksort(int A[],int p,int r);
void swap(int *x,int *y){int t; t=*x; *x=*y; *y=t; }
int main(int argc,char *argv[])
{
int A[100]={5,4,3,2,1};
int n=5;
quicksort(A,0,n-1);
for(int i=0;i<n;i++)
printf("%3d",A[i]);
return 0;
}
void quicksort(int A[],int p,int r)
{
if(p>=r) return;
int q=partition(A,p,r);
//根據主元的位置進行遞迴求解
quicksort(A,p,q-1);
quicksort(A,q+1,r);
}
int partition(int A[],int p,int r)
{
int x=A[r];//以這個元素為主元,即拿這個元素與其他元素比較
int i=p-1;//i為最左邊元素減一
//其中,從p到i為小於等於x的子陣列1,而從i+1到j為大於等於x的子陣列2,
//從j+1到r-1表示的是還未進行分配的子陣列
//而元素r為主元
for(int j=p;j<=r-1;j++)
{
if(A[j]<=x)
{
i++;//子陣列1加入一個元素
//加一後的i大於等於x
swap(A+i,A+j);
//交換後其恢復原來“秩序”
}
}
swap(A+i+1,A+r);//把主元放到合適的位置。
return i+1;//返回主元的位置
}
其實其核心就是分割陣列。
其把陣列分為四個部分:
1.從p到i為小於等於x的子陣列1,而
2.從i+1到j為大於等於x的子陣列2,
3.從j+1到r-1表示的是還未進行分配的子陣列
4.元素r為主元
最後把r放到陣列1和陣列2的中間位置
partition函式的時間複雜度為Θ(n)
快速排序的效能:
快速排序的執行時間依賴與劃分是否平衡,如果劃分是不平衡的,那麼其效能就接近插
入排序了
最壞情況劃分:
當劃分產生兩個子問題分別包含了n-1個元素和0個元素時,快速排序的最壞情況為
Θ(n^2)
其表示式為T(n)=T(n-1)+Θ(n)
利用主方法,其時間複雜度為Θ(n^2)
最好情況的劃分
在最可能平衡的劃分中,就是兩個子陣列長度相等或差1,這時,其T(n)=2*T(n/2)+Θ(n)
利用主方法 其時間複雜度為Θ(n*lg(n))
平衡的劃分:
快速排序的平均執行時間更接近與其最好情況下的效能,而不是最壞情況下的效能。
假設演算法為9:1劃分,
利用一個遞迴樹,表示,
其T(n)=T(9*n/10)+T(n/10)+Θ(n)
其每層的代價和為cn
一共有log(10/9) n=Θ(lg(n))層
所以其時間複雜度為O(n*lg(n))
99:1仍然一樣,其時間複雜度為O(n*lg(n)),,因為其層數為log(100/99) n=Θ(lg(n))層
其實,任何一種常數比例的劃分都會產生深度為Θ(lg(n))層的遞迴樹,其中每層代價都為
O(n),所以只要劃分為常數比例的,其演算法的執行時間為O(n*lg(n))
對於平均情況的直接觀察:
當好和差的劃分交替出現時,快速排序的時間複雜度與全是好的劃分一樣,仍然是
O(n*lg(n))。區別只是O的符號中隱含的常數因子要略大一些。
快速排序的隨機化版本:
在這裡不用對輸入的陣列進行隨機排序,只需隨機選取其主元就可以滿足隨機化演算法
這樣劃分就可以滿足隨機條件
下面上程式碼:
/*************************************************************************
> File Name: quicksort.cpp
> Author:chudongfang
> Mail:1149669942@qq.com
> Created Time: 2016年06月28日 星期二 21時11分41秒
************************************************************************/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int partition_random(int A[],int p,int r);
void quicksort_random(int A[],int p,int r);
void swap(int *x,int *y){int t; t=*x; *x=*y; *y=t; }
int main(int argc,char *argv[])
{
srand(time(0));
int A[100]={5,4,3,2,1};
int n=5;
quicksort_random(A,0,n-1);
for(int i=0;i<n;i++)
printf("%3d",A[i]);
return 0;
}
void quicksort_random(int A[],int p,int r)
{
if(p>=r) return;
int q=partition_random(A,p,r);
//根據主元的位置進行遞迴求解
quicksort_random(A,p,q-1);
quicksort_random(A,q+1,r);
}
int partition_random(int A[],int p,int r)
{
int y=p+rand()%(r+1-p);//隨機交換A[r]
swap(A+y,A+r);
int x=A[r];//以這個元素為主元,即拿這個元素與其他元素比較
int i=p-1;//i為最左邊元素減一
//其中,從p到i為小於等於x的子陣列1,而從i+1到j為大於等於x的子陣列2,
//從j+1到r-1表示的是還未進行分配的子陣列
//而元素r為主元
for(int j=p;j<=r-1;j++)
{
if(A[j]<=x)
{
i++;//子陣列1加入一個元素
//加一後的i大於等於x
swap(A+i,A+j);
//交換後其恢復原來“秩序”
}
}
swap(A+i+1,A+r);//把主元放到合適的位置。
return i+1;//返回主元的位置
}
快速排序分析:
最壞情況分析
T(n)=max(T(q)+T(n-q-1))+Θ(n)
不妨猜測T(n)<=c*n^2
代入得 T(n)<=max(c*q^2+c(n-q-1)^2)+Θ(n)
二次函式的上界為n^2-c(2*n-1)
又有:n^2-c(2*n-1)+Θ(n)<=c*n^2
可以選擇一個c使得c(2*n-1)>Θ(n)
Θ(n)-c(2*n-1)<0
期望執行時間:
我們首先對陣列A的各個元素重新進行命名,z1,z2,z3,,,,zn
代表第i大的元素。
另外還定義z[i][j]為{zi,zi+1,,,,,zj}的集合。
這裡利用了指示器隨機變數X[i][j]代表了{zi和zj進行比較}
然後對於一個集合z[i][j]有 2/(j-i+1)的概率比較
(這裡只有在主元選取zi和zj時能夠進行比較,因為如果選取
中間元素的話,就把兩個分割就無法進行比較)
然後根據求和
i: 1=>n-1
j: i+1=>n
sum+= 2/(j-i+1)
最後後得到E[x]=O(n*lg(n))
所以在隨機演算法和輸入互異的情況下,快速演算法的
期望執行時間為O(n*lg(n))
相關文章
- 演算法導論-快速排序演算法排序
- 演算法導論學習之五:快速排序演算法排序
- 演算法導論-堆排序演算法排序
- 排序演算法__快速排序排序演算法
- 排序演算法:快速排序排序演算法
- 排序演算法-快速排序排序演算法
- 排序演算法——快速排序排序演算法
- 排序演算法 - 快速排序排序演算法
- 《快速排序》引發關於演算法的討論排序演算法
- 演算法導論_第六章_堆排序演算法排序
- 演算法導論學習之六:歸併排序演算法排序
- 演算法導論學習之二:插入排序演算法排序
- 演算法導論學習之一:氣泡排序演算法排序
- 排序演算法之 '快速排序'排序演算法
- #排序演算法#【4】快速排序排序演算法
- 《排序演算法》——快速排序(Java)排序演算法Java
- 【JAVA演算法】排序演算法 -- 快速排序Java演算法排序
- 【演算法】快速排序演算法排序
- 快速排序演算法排序演算法
- 從零開書學演算法(導論)之歸併排序演算法排序
- 排序演算法-Java實現快速排序演算法排序演算法Java
- 演算法之旅:快速排序演算法排序
- 演算法之快速排序演算法排序
- 排序演算法 - 快速插入排序和希爾排序排序演算法
- 三種快速排序演算法以及快速排序的優化排序演算法優化
- 《演算法導論》演算法
- 畫江湖之演算法篇【排序演算法】快速排序演算法排序
- 畫江湖之演算法篇 [排序演算法] 快速排序演算法排序
- java:快速排序演算法與氣泡排序演算法Java排序演算法
- 前端演算法:快速排序演算法前端演算法排序
- 演算法之常見排序演算法-氣泡排序、歸併排序、快速排序演算法排序
- 演算法導論_第八章_線性時間排序演算法排序
- 排序演算法之快速排序的實現排序演算法
- Sorting 排序演算法: Quick Sort 快速排序排序演算法UI
- 看動畫學演算法之:排序-快速排序動畫演算法排序
- 經典排序演算法 - 快速排序Quick sort排序演算法UI
- 演算法導論學習之三:排序之C語言實現:選擇排序,插入排序,歸併排序演算法排序C語言
- 演算法 | 快速排序詳解演算法排序