首页 > 其他分享 >深入理解快速排序

深入理解快速排序

时间:2024-03-12 18:58:19浏览次数:19  
标签:移动 数组 int 元素 理解 深入 key 排序

一、快速排序

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

算法过程分析:

        通过采用分治策略,围绕一个 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;
}

标签:移动,数组,int,元素,理解,深入,key,排序
From: https://blog.csdn.net/Zhang_Qin123/article/details/136655006

相关文章

  • 探索Flutter中的模糊毛玻璃滤镜效果:ImageFilter介绍使用和深入解析
    在Flutter中,模糊效果不仅可以增加应用的视觉吸引力,还可以用于多种场景,如背景模糊、图像处理等。通过BackdropFilter和ImageFilter.blur,Flutter使得添加和调整模糊效果变得异常简单。本文将深入探讨如何在Flutter中实现动态模糊效果,并通过TileMode参数调整模糊效果的边缘行为......
  • ABAP SALV-排序、过滤
    01功能说明上篇:ABAPSALV-按钮设置、布局设置本系列将通过模拟用户与开发者之间的对话场景,来逐步演示SALV的使用。在本篇中,我们将继续上一篇内容,以解决用户提出的另外两个需求:排序、过滤。让我们来看看是如何实现的吧。赶快动手试一试,掌握它的用法。02功能效果第6天......
  • 你是怎么理解ES6中Module的?使用场景?
    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助一、介绍模块,(Module),是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体)。两个基本的特征:外部特征和内部特征外部特征是指模块跟外部环境联系的接口(即其他模块或程序调用该模块的......
  • 【算法】【线性表】【数组】在排序数组中查找元素的第一个和最后一个位置
    1 题目给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1,-1]。你必须设计并实现时间复杂度为 O(logn) 的算法解决此问题。示例1:输入:nums=[5,7,7,8,8,......
  • 深入理解 Nginx:原理和基础介绍
    简介Nginx(发音为"engine-x")是一个高性能的开源Web服务器,它也可以用作反向代理服务器、负载均衡器、HTTP缓存以及作为邮件代理服务器。它的灵活性、高性能和可扩展性使其成为许多互联网公司和网站的首选服务器软件。本文将介绍Nginx的原理、基础知识以及其在互联网架构中的......
  • 深入理解 ELK 中 Logstash 的底层原理 + 填坑指南
    深入理解ELK中Logstash的底层原理+填坑指南<imgsrc="https://pic4.zhimg.com/v2-3afecd9bcad8087524ef7db1f8f51abf_b.jpg"data-rawwidth="722"data-caption=""data-size="normal"data-rawheight="500"class="origi......
  • springboot-02理解 自动配置原理
    在进行springboot的多环境配置:可以选择激活那一共配置文件在properties下使用spring.profiles.active=.dev.test等在yaml下可以使用-------来进行分割环境配置测试环境server:port:8082spring:Profiles:dev/test;active:只需通过选择不同调用的环境参数进行声明即可......
  • 深入探索Spring注入:解锁@Autowired与构造器注入的秘密
    好久没有写JAVA了今天突然看到Sonarlint的提示  什么??竟然不推荐这样写?难道我一直写的都是错的??所以我深入了解了一下为什么要我改成构造函数注入在Spring框架中,依赖注入(DI)是一种核心功能,它允许对象通过构造函数、setter方法或字段直接定义其依赖关系。这里,我们专注于两种......
  • SQL 多关键字查询并根据匹配程度排序
    --创建测试表IFEXISTS(SELECT*FROMsys.objectsWHEREobject_id=OBJECT_ID(N'[dbo].[Score]')ANDtypein(N'U'))DROPTABLE[dbo].[Score]GOCREATETABLE[dbo].[Score]([Id][int]IDENTITY(1,1)NOTNULL,[UserName][nvarchar](50......
  • 《深入理解Java虚拟机》 读书
    根据之前的读书计划,我本应该阅读《Tom的设计模式》这本书。然而,由于一些原因,我不得不提前将图书馆借阅的书归还,因此我转而开始阅读《深入理解Java虚拟机》。至于设计模式,我还有一本小傅哥的书籍,我会再稍后找时间阅读。《深入理解Java虚拟机》这本书我已经从年前开始阅读了,由于过......