快速排序算法分析和實現


快速排序的思想:

選擇一個基准元素,比基准元素小的放基准元素的前面,比基准元素大的放基准元素的后面,這種動作叫分區,每次分區都把一個數列分成了兩部分,每次分區都使得一個數字有序,然后將基准元素前面部分和后面部分繼續分區,一直分區直到分區的區間中只有一個元素的時候,一個元素的序列肯定是有序的嘛,所以最后一個升序的序列就完成啦

但是關於基准元素的選擇有兩種

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;
}
View Code

算法分析:

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;
}
View Code

總結:快排雖然不穩定,但是高效(關於不穩定的概念請百度。。。)

    

有錯誤的地方麻煩大佬們指正!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM