交换排序—快速排序

排序思路

在待排序数列中任取一个元素(通常是第一个元素作为基准),将所有大于该元素的元素放入一边,所有小于该元素的元素放入另一边。这一过程叫做一趟快速排序。接着对左右两边进行上面重复操作,直到每一个部分内只有一个元素或为空。

对于无序数组a[n]采用从两头向中间扫描,同时交换与基本元素逆序的元素。具体做法:设两个指针i和j最初指向无序区的第一个元素和最后一个元素,将第一个元素a[i]放入临时变量tmp中作为基准,当i不等于j时,从右向左扫描,直到发现a[j]<tmp为止,将a[j]赋值给a[i];然后从左向右扫描,当i不等于j时,直到发现a[i]>tmp为止,将a[i]赋值给a[j];直到i=j时,停止扫描,将tmp赋值给a[i]。这样基准元素归位了,再对左右无序区重复上面的操作,直到无序区元素为1个或0个。

代码实现

#include <iostream>

using namespace std;

//快速排序,传入参数:待排数列,数列左右两端
void QuickSort(int a[],int l,int r){
    int i=l,j=r,tmp;
    if(l<r){//无序区间至少存在两个元素
        tmp=a[l];//用区间第一个元素作为基准
       while(i!=j){//从区间两端交替向中间扫描,直到i=j
        //从右向左扫描,直到出现小于tmp
        while(j>i&&a[j]>tmp)
            j--;
        a[i]=a[j];//找到这样的a[j],将a[j]\a[i]交换
        while(i<j&&a[i]<tmp)
            i++;
        a[j]=a[i];
       }
       a[i]=tmp;//将基准归位
       QuickSort(a,l,i-1);//递归左区间
       QuickSort(a,i+1,r);//递归有区间
    }
}

int main()
{
    int a[]={0,9,8,7,6,5,4,3,2,1};
    QuickSort(a,0,9);
    for(int i=0;i<10;i++){
        cout << a[i] <<",";
    }
    cout<< endl;
    return 0;
}

算法分析

快速排序的主要时间耗费在划分上面,对于长度的n的区间划分,需要n-1次关键词比较。最坏情况是选择的基准为无序区中最小值或最大值,这样划分结果是左边子区间或右边子区间为空。而划分所得的另一个非空子区间中元素的数目,仅仅比划分前的无序区中元素个数少一个。因此对于长度为n的数列,需进行n-1次划分,其中第i次划分开始区间长度为:n-i+1,需要n-i(1<=i<=n-1)。

最大比较次数:C_{max}=\sum_{i=1}^{n-1}(n-i)=\frac{n(n-1)}{2}=O(n^2)

最好情况,每次划分选取的基准都是当前无序区的“中值”元素,划分的结果是基准左、右两个无序区的长度大致相等。对于长度为n的序列,需要比较n-1次,加上左右子区间(长度<=n/2)的比较次数2C(n/2)。C(n)=n-1+2C(n/2)。为了方便计算,这里将长度假设为 n=2^k,C(n)=n-1+2C(n/2)\approxn+2C(n/2)

最小比较次数:

C(n)\leqslant n+2C(\frac{n}{2}) \leqslant n+2(\frac{n}{2}+2C(\frac{n}{2^2})) \leqslant 2n+4C(\frac{n}{2^3})\leqslant \cdots \leqslant kn+2^kC(\frac{n}{2^k})\leqslant nlog_{2}^n+nC(1)=O(nlog_{2}^n)

通过对公式展开合并,可以发现规律kn+2^kC(\frac{n}{2^k}) 其中k=log_{2}^n,C(1)表示对于长度为1的区间进行排序所需的比较次数,可以看作一个常数。最后得到最好情况的比较次数:O(nlog_{2}^n)

平均情况:可以设当基准为i位置时(1<=i<=n),可以得到平均时间:T(n)

T(n)=n+\frac{1}{n}\sum_{i=1}^{n}(T(i-1)+T(n-i))=O(nlog_{2}^n)

具体推算过程省略,其中思路上上面一样,首先对于长度为n的数列,第一次需要比较n-1次,因为基准位置为i,则第一次划分后,左右两边的无序区长度分别为(i-1)和(n-i),其中i的可能性为:1-n。

平均比较次数O(nlog_{2}^n)

空间复杂度考虑到每轮使用i,j,tmp3个变量,最好时递归次数需要O(log_{2}^n),最坏时递归次数O(n)。

平均空间复杂度:O(log_{2}^n)

快速排序是不稳定的排序算法。

猜你喜欢

转载自blog.csdn.net/SICAUliuy/article/details/88910381