ACM--快速排序算法(选择第一个元素,中位数,随机数作为基准值) 分析其时间和空间复杂度。

 快速排序算法是冒泡排序算法的一种优化,我们知道冒泡排序算法是两层for循环嵌套,时间复杂度为O(N^2),并且每次移动的距离短,每次比较的元素都是相邻的元素。所以快速排序就弥补了这个缺点。

快排选用不同的规则的基准都是在选择固定基准(第一个元素,最后一个元素,中间元素)的基础上得来的,最核心的比较:以其中一个元素为基准比较为例:循环遍历左侧是否有比自己大的元素,右侧是否有比自己小的元素,将两个元素互相交换,然后再递归处理左右两个数组元素即可,具体代码如下:

AcWing 785. 快速排序

下面以一道例题为例:

给定你一个长度为 nn 的整数数列。

请你使用快速排序对这个数列按照从小到大进行排序。

并将排好序的数列按顺序输出。

输入格式

输入共两行,第一行包含整数 nn。

第二行包含 nn 个整数(所有整数均在 1∼1091∼109 范围内),表示整个数列。

输出格式

输出共一行,包含 nn 个整数,表示排好序的数列。

数据范围

1≤n≤1000001≤n≤100000

输入样例:
5
3 1 2 4 5
输出样例:
1 2 3 4 5

一.以第一个元素为基准

比较冗杂一般的代码 

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
const int N = 1e6+10;
int vec[N];
//分隔
int partition(int vec[], int i, int j)
{
    while (i < j)
    {
        while (i < j && vec[i] <= vec[j])
            j--;
        if (i < j)
        {
            swap(vec[i], vec[j]);
            i++;
        }

        while (i < j && vec[i] <= vec[j])
            i++;
        if (i < j)
        {
            swap(vec[i], vec[j]);
            j--;
        }
    }
    return i;
}

void quickSort(int vec[], int i, int j)
{
    if (i < j)
    {
        int pos = partition(vec, i, j);
        quickSort(vec, i, pos - 1);
        quickSort(vec, pos + 1, j);
    }
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0;i < n;i++)
    {
        int num = 0;
        scanf("%d", &num);
        vec[i] = num;
    }
    quickSort(vec, 0, n-1);
    for (int i = 0;i < n;i++)
    {
        printf("%d ", vec[i]);
    }
    return 0;
}

二.以中位数为基准 

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
const int N = 1e6+10;
int vec[N];
//分隔
//取中位数作为分隔进行快速排序
int findMedianIndex(int vec[],int first,int middle,int end)
{
    return (vec[first] > vec[middle])
        ? ((vec[middle] > vec[end]) ? middle : ((vec[first] > vec[end]) ? end : first))
        : ((vec[first] > vec[end]) ? first : ((vec[middle] > vec[end]) ? end : middle));       
}

int partition(int vec[], int i, int j)
{
    int pivotIndex = findMedianIndex(vec, i, (i + j) / 2, j);
    swap(vec[i], vec[pivotIndex]);
    while (i < j)
    {
        while (i < j && vec[i] <= vec[j])
            j--;
        if (i < j)
        {
            swap(vec[i], vec[j]);
            i++;
        }

        while (i < j && vec[i] <= vec[j])
            i++;
        if (i < j)
        {
            swap(vec[i], vec[j]);
            j--;
        }
    }
    return i;
}

void quickSort(int vec[], int i, int j)
{
    if (i < j)
    {
        int pos = partition(vec, i, j);
        quickSort(vec, i, pos - 1);
        quickSort(vec, pos + 1, j);
    }
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0;i < n;i++)
    {
        int num = 0;
        scanf("%d", &num);
        vec[i] = num;
    }
    quickSort(vec, 0, n-1);
    for (int i = 0;i < n;i++)
    {
        printf("%d ", vec[i]);
    }
    return 0;
}

三. 以随机数为基准 

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6+10;
int vec[N];
void quick_sort(int vec[],int i,int j)
{
    if(i >= j) return;
    //取随机数看能否能过
    int num = (int)(1.0*rand()/RAND_MAX*(j-i)+i);
    swap(vec[i],vec[num]);
    int x = vec[i],l = i-1,r = j+1;
    while(i < j)
    {
        do l++; while(vec[l] < x);
        do r--; while(vec[r] > x);
        if(l < r) swap(vec[l],vec[r]);
    }
    quick_sort(vec,i,l-1);
    quick_sort(vec,l+1,j);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0;i < n;i++)
    {
       scanf("%d",&vec[i]);
    }
    /*quickSort(vec, 0, n-1);*/
    sort(vec,vec+n);
    for (int i = 0;i < n;i++)
    {
        printf("%d ", vec[i]);
    }
    return 0;
}

 分析其时间复杂度:

在最好的情况O(nlog2n):最好的情况就是每次划分的左右两个数组长度完全相同。怎么说呢

每一组数组的快排时间复杂度为O(n)。递归的深度就是完全二叉树的深度nlog2n所以相乘可得。

最坏的情况就是O(n^2):就是当差不多已经排好序的情况下,分成的两组元素一组为空,递归的深度此时就是数组的大小。

空间复杂度就是递归的深度,他会占用系统额外的内存。

最好情况的系统开销就是完全二叉树的深度log2n

最坏情况的开销就是o(n)

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值