20-考研-数据结构-快速排序

上一节我们写了关于冒泡排序的内容,但是在算法执行效率上却牺牲了太多,时间复杂度达到了N^2,相比较桶排序浪费空间相比,有没有一个既不浪费时间又不浪费空间的算法呢,那就是快排了。

算法思想:

从一个序列中找一个基准数,用来参照(一般选第一个数字),接下来需要将这个序列中所有比基准数大的数字放在基准的右侧,所有比基准小的数字放在基准的左侧。

分别从两端开始探测,先右后左,相遇说明此时探测结束

基本图示:

20-考研-数据结构-快速排序

举个粒子:

初始序列:6 1 2 7 9 3 4 5 10 8

从两端探测,以第一个数字6位基准,先从右侧开始找到一个比6小的数字(哨兵j),再从左边往侧找到一个比6大的数字(哨兵i),并且交换他们,j一步一步往左挪动(j--),直到找到一个小于6的数字5停下来,接下来i从左往右挪动(i++),直到找到一个大于6的数字7停止,交换i和j两个哨兵所指向的元素,序列为 6 1 2 5 9 3 4 7 10 8  ,第一次交换结束,j继续向左边挪动(每次都必须是j先移动),走到了4的位置,i向右挪动走到了9的位置,交换两个数字,此时的序列为 6 1 2 5 4 3 9 7 10 8  ,第二次交换结束了。j继续向左移动,到了3的位置,停止移动,i继续向右侧移动,此时i和j相遇在3所在的位置,说明此时的探测结束了,我们最后需要将基准6和3进行交换,此时序列为

3 1 2 5 4 6 9 7 10 8 ,第一轮探测结束。  现在基准6已经归位了,6左侧的都比6小,右侧都比6大。

我们将原来的序列以6为分界,分成两个序列,左侧 3 1 2 5 4  右侧  9 7 10 8  接下来分别处理这连个序列,左侧以3为基准。。。。。。。。。。。。。。。。(人的本质是什么?当然是重复啊!)

分析时间复杂度:

快排之所以快,是因为相比冒泡,他的每次交换都是跳跃式的,总的比较和交换次数少了,速度自然就提高了。当然在最坏的情况下仍可能是相邻的两个数字进行比较和交换。因此快排的最差时间复杂度和冒泡是一样的O(N^2),平均复杂度为O(NlogN),其实是基于二分的思想。

时间复杂度数学证明:https://blog.****.net/huanting74/article/details/79794728

代码演示:

10

10 6 1 2 7 9 3 4 5 10 8

#include<stdio.h>
#include<iostream>
using namespace std;
#define maxSize 100
//定义全局变量数组,在子函数中会用到
int a[maxSize],n;

//快速排序函数
void quickSort(int left,int right){
    if(left>right){
        return;
    }
    int temp=a[left];
    int i=left;
    int j=right;
    while(i!=j){
        //顺序很重要,需要先从右边往左边找
        while(a[j]>=temp&&i<j){
            j--;
        }
        while(a[i]<=temp&&i<j){
            i++;
        }
        //交换两个数字的位置
        if(i<j){//当没有相遇时候
            int t=a[i];
            a[i]=a[j];
            a[j]=t;
        }
    }
    //最终将基准归位
    a[left]=a[i];
    a[i]=temp;
    quickSort(left,i-1);//继续处理左侧
    quickSort(i+1,right);//继续处理右侧
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    quickSort(0,n-1);//调用快速排序函数

    //输出快排之后的结果
    for(int i=0;i<n;i++){
        printf("%d ",a[i]);
    }
    return 0;
}

代码结果展示;

20-考研-数据结构-快速排序