快速排序算法及时间复杂度分析(原地in-place分区版本)

来源:互联网 发布:中京创意域名交易平台 编辑:程序博客网 时间:2024/06/11 23:04

快速排序算法一般来说是采用递归来实现,其最关键的函数是partition分割函数,其功能是将数组划分为两部分,一部分小于选定的pivot,另一部分大于选定的pivot。我们将重点放在该函数上面。

partition函数总体思路是自从一边查找,找到小于pivot的元素,则将其放到前面去,这样要达到的目的是使小于pivot的元素全部在前面,则大于pivot的元素就必然都在后面了。要达到此目的,有一点必须注意,就是在讲小于pivot的元素放到前面去的时候,一定要是紧挨着存放,否则空隙里面放的就可能会是大于pivot的元素,所以我们设置了一个storeIndex变量,并初始化为left来依次紧挨着存放小于pivot的元素。

由于刚开始并不知道最后pivot的存放位置,所以,需要先将pivot交换到后面去(如果是将大的元素依次放到后面就不需要这样的交换),然后遍历数组,找到小于的pivot的元素,就将其放到storeIndex处,并将storeIndex加1。在partition函数最后将pivot交换到storeIndex处。

在quicksort函数中,应特别注意!首先应当判断left时候小于right,以此作为递归返回的条件,还需根据条件设置pivot。

至于时间复杂度,考虑平均复杂度,即每次都是均等二分,一共会有logn层,每层都会遍历到数组几乎所有元素,为O(n),所以直观上我们可以看出平均复杂度为O(nlogn)。而,同理最坏时间复杂度为O(n^2)。正规分析如下:

平均时间复杂度T(n)=O(n)+2T(n/2),最坏复杂度T(n)=O(n)+T(n-1)。通过推导,我们也很容易得到上述结论。

代码如下:

#include<iostream>using namespace std;int a[] = { 1, 2, 8, 7, 9, 5, 6, 4, 3, 66, 77, 33, 22, 11 }; //用于测试,从小到大排序/* 输出数组前n各元素 */void prt(int n){    int i;    for (i = 0; i < n; i++)    {        printf("%d\t", a[i]);    }    printf("\n");}/*交换两值*/void swap(int &p,int &q){int temp=p;p=q;q=temp;}/*划分函数*/int partition(int a[],int left,int right,int pivotIndex) // 将pivotIndex的选取放在函数外面做{int pivotValue=a[pivotIndex];swap(a[pivotIndex],a[right]); //将pivot放到结尾int storeIndex=left; // 用于指示比pivotValue值小的数值应该存放的位置for(int i=left;i<right;i++){if(a[i]<pivotValue) // 找到了比pivotValue小的值{swap(a[i],a[storeIndex]);storeIndex++;}}swap(a[storeIndex],a[right]); //将pivot放到其最终的位置上return storeIndex;}void quicksort(int a[],int left,int right){if(left<right) //该判断很重要{int pivotIndex=left; //选取pivotint pivotNewIndex=partition(a,left,right,pivotIndex);quicksort(a,left,pivotNewIndex-1);quicksort(a,pivotNewIndex+1,right);}}int main(void) {    /* 排序与输出 */    quicksort(a, 0, 13);    prt(14);    return 0;}

0 0