快速排序的思想:
選擇一個基准元素,比基准元素小的放基准元素的前面,比基准元素大的放基准元素的后面,這種動作叫分區,每次分區都把一個數列分成了兩部分,每次分區都使得一個數字有序,然后將基准元素前面部分和后面部分繼續分區,一直分區直到分區的區間中只有一個元素的時候,一個元素的序列肯定是有序的嘛,所以最后一個升序的序列就完成啦
但是關於基准元素的選擇有兩種
1.第一種是每次都選序列的子序列的第一個元素(有缺陷)
2.第二種是每次都選擇子序列中的第x個元素,x隨機
普通快速排序
代碼如下:

#include<bits/stdc++.h> using namespace std; #define n 5 int a[n]; void swap_t(int a[],int i,int j) { int t=a[i]; a[i]=a[j]; a[j]=t; } int par(int a[],int p,int q) { int i=p;//p是軸 int x=a[p];//基准元素 for(int j=p+1;j<=q;j++) { if(a[j]<=x)//升序 { i++; swap_t(a,i,j); } } swap_t(a,p,i); return i;//軸位置 } void QuickSort(int a[],int p,int q) { if(p<q)//序列中元素個數大於1 { int r=par(a,p,q); QuickSort(a,p,r-1); QuickSort(a,r+1,q); } } int main() { int i; for(i=0;i<n;i++) { scanf("%d",&a[i]); } QuickSort(a,0,n-1); for(i=0;i<n;i++) { printf("%d\n",a[i]); } return 0; }
算法分析:
1.最好情況:(每次分區時子序列中元素個數相同)
T(n)=2T(n/2)+O(n)=O(n*logn) log的底是2
2.最壞情況:序列是由大到小排序的
比如:7 6 5 4 3 2 1 -----> ( 進行依次分區,基准元素是7) 1 6 5 4 3 2 7,元素7的后面是沒有元素的,同理 再將序列1 6 5 4 3 2分區,變成了1 2 5 4 3 6,分區6的后面也是沒有元素的(7不屬於這個分區),所以最壞情況的快速排序相當於冒泡排序了。。。。。。。有沒有一種操蛋的感覺
T(n)=T(1)+T(n-1)+O(n)
=T(1)+T(1)+T(n-2)+T(n-1)+O(n-1)+O(n)
繼續變形下去
T(常數)可以去掉
T(n)=O(1)+O(2)+.......+O(n)//等差數列求和
T(n)=O((1+n)*n/2)=n*n //常數可以省略
所以T(n)=n*n
3.一般情況:
T(n)=T(n/5)+T(4*n/5)+O(n) //假設前面分成1份后面分成4份這種情況
=T(n/25)+T(4*n/25)+O(n/5)+T(4*n/25)+T(16*n/25)+O(4*n/5)
我們假設T(n/5) 和T(4*n/5)展開成一顆樹的形狀,經過一系列比較復雜的推導之后(不好描述。。。。。)得到樹的最大深度是log 5/4 n(底數的5/4),然后log 5/4 n 經過數學等價變形為log 2 n(底數為2)
然后又經過一系列復雜推導后(。。。。。。。。。。),樹的最大寬度為:n
所以T(n)=n*log 2 n(底數為2)
總結:普通快排存在缺陷,缺陷在於每次基准元素的選擇
二,改進之后的快速排序:隨機化快速排序(每次隨機在序列中選擇基准元素),因為快排的性能取決於划分的對稱性
附加知識:生成p,q之間的隨機數:
方法:先生成隨機數n,int i=n%(q-p+1)+p ,i就是p,q之間的隨機數
代碼如下:

#include<bits/stdc++.h> using namespace std; #define n 5 int a[n]; void swap_t(int a[],int i,int j) { int t=a[i]; a[i]=a[j]; a[j]=t; } int par(int a[],int p,int q) { int i=p;//p是軸 int x=a[p]; for(int j=p+1;j<=q;j++) { if(a[j]<=x) { i++; swap_t(a,i,j); } } swap_t(a,p,i); return i;//軸位置 } int Random(int p,int q) { return rand()%(q-p+1)+p; } int Randomizedpar(int a[],int p,int q) { int i=Random(p,q); swap_t(a,p,i);//第一個和第i個交換,相當於有了一個隨機基准元素 return par(a,p,q); } void RandomizedQuickSort(int a[],int p,int q) { if(p<q) { int r=Randomizedpar(a,p,q); printf("%d到%d之間的隨機數:%d\n",p,q,r); RandomizedQuickSort(a,p,r-1); RandomizedQuickSort(a,r+1,q); } } int main() { int i; for(i=0;i<n;i++) { scanf("%d",&a[i]); } RandomizedQuickSort(a,0,n-1); for(i=0;i<n;i++) { printf("%d\n",a[i]); } return 0; }
總結:快排雖然不穩定,但是高效(關於不穩定的概念請百度。。。)
有錯誤的地方麻煩大佬們指正!!!