深入理解快速排序

本文详细介绍了快速排序算法的工作原理,包括选择基准元素、划分子数组和递归过程。同时对比了快速排序与冒泡排序的时间复杂度,并探讨了优化方法,如使用随机基准值。最后提到了C++中的sort()函数作为另一种排序手段。
摘要由CSDN通过智能技术生成

一、快速排序

        快速排序是冒泡排序的一种改进算法,相比于冒泡排序效率更优。

算法过程分析:

        通过采用分治策略,围绕一个 x 将原始数组划分为两个子数组,使得前一个子数组的元素≤ x ≤ 后一个子数组元素,对两个子数组进行递归排序,再合并成一个有序数组。

        1.选取一个基准元素 key(通常默认为数组的最左端),通过 key 将数组分为左右两端,使得左端数组全部 ≤ 基准元素 key ,右端数组全部元素 ≥ 基准元素key。

        2.两端数组可以独立排序。对于左端数组,又可以取一个基准元素,将该端数组元素分成左右两部分,使得左端数组全部 ≤ 基准元素 key ,右端数组全部元素 ≥ 基准元素key。右侧数组做类似处理。

        3.通过递归重复上述操作,当全部递归结束时,原数组也排序完成。

 细节分析:

        步骤1:将数组如何分成两个子数组,使得左端数组全部 ≤ 基准元素 key ,右端数组全部元素 ≥ 基准元素key

①j从右向左,找到小于key的数组元素

②i从左向右,找到大于key的数组元素,将二者交换。

③上述操作直至 i==j 时结束 

④此时再将基准值与 a[i](或a[j],i==j)交换,就使得两个子数组上述条件成立。

int i=left,j=right;
while(i!=j)
{
	while(a[j]>=temp && i<j) j--;
	while(a[i]<=temp && i<j) i++;
	swap(a[i],a[j]);
}
swap(a[left],a[i]); 

         步骤2:

分治策略,将左右两个子数组进行相同的操作。

quick_sort(left,i-1);
quick_sort(i+1,right);

 重复操作,通过递归分别进入两个子数组操作。

当全部返回时,结束递归,数组完成排序。

        思考:为什么 i 从左往右移动,j从右往左移动时,j 先移动?

  因为当 i 先移动时,i 一定会往右至少移动一次,出现以下情况:

① i 不停移动,直至移动到数组右端,此时交换i,j,出现错误,如图。

② i 先移动,移动到中间某个点时,j再移动,移动到i,j相等时交换,出现错误。

相反,如果是 j 先移动, 都能使得正确交换,必须先找到小于基准值key的元素

二、快速排序完整代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int a[10001];
int n;
void swap(int a1,int b1)    {int w=a[a1];a[a1]=a[b1];a[b1]=w;}  //交换函数
void qsort1(int begin,int end) // 快排的实现
{
    if(begin > end)  return ;  // 退出快排函数 避免出现死循环
    int tem=a[begin];    // 记录基准点
    int i=begin,j=end;
    while(i!=j)
    {
        while(a[j]>=tem && i<j)   j--;  //从右边开始找小于基准点的数
        while(a[i]<=tem && i<j)   i++;  //从左边开始找大于基准点的数
        if(i<j) swap(i,j);    
    }
    a[begin]=a[i]; // 交换基准点和第i个 确保基准点左边全部比其小 右边全部不它大
    a[i]=tem;
    qsort1(begin,i-1);  // 继续分成两个部分进行快速排序
    qsort1(i+1,end);
 
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    qsort1(1,n);
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
   // system("pause");
    return 0;
}

三、算法的性能分析

时间复杂度:

        理想情况:每次都尽可能将左端数组和右端数组等分递归,这样通过计算得出

                T(n)=2T(\frac{n}{2})+\Theta (n)

           时间复杂度与归并排序相同,为  O(nlogn) 

        最差情况:不难发现,当排序数组为顺序或者逆序时,每次 i,j 的移动都是从左到右

                时间计算 会与冒泡排序相同        复杂度为 O(n^{2})

            一般情况下,快速排序的时间复杂度为 O(nlogn),但是不稳定。

  洛谷—排序P1177  这道题,数据仍然卡快速排序,时间复杂度来到  O(n^{2}) ,需要对其进行优化。

四、快速排序优化

         上述快速排序总是将基准值默认为数组中第一个元素,当数组成顺序或者逆序时,出现最慢的情况。

        优化方法:在排序数组中随机选择一个数作为基准数进行排序。

基准数随机的结果:

         ①运行时间与输入数据的次序无关

        ②无特定输入数据匹配最差情况

        ③最差情况仅仅由随机数生成器所决定

对随机化快速排序的时间复杂度:O(nlogn)  (不稳定)

四、sort() 函数

        在C++中使用sort()函数需要使用#include<algorithm>头文件。algorithm意为"算法",是C++的标准模版库(STL)中最重要的头文件之一,提供了大量基于迭代器的非成员模版函数。

 可以简单使用 sort() 函数对数组进行排序

#include<stdio.h>
#include<string.h>
#include<algorithm>
int main()
{
    int n,a[10001];
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+1+n); // 使数组从  a[1] 到 a[n] 排序
    for(int i=1;i<=n;i++) printf("%d ",a[i]);
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值