数据结构与算法学习(day3)——快速排序

文章目录

  • 前言
  • 复习冒泡排序时遇到的问题
  • 快速排序

前言

(1)在本章的学习此前,需要复习前一章的内容,动手敲一遍解题。上一章讲的是冒泡排序算法,我在回顾的时候重新敲了一遍重新,就发了一些问题,改Bug改了一个下午,虽然时间有点久,毕竟是刚开始学,但是我也更深刻的理解了冒泡排序的算法原理,也对它有了更深的研究,也明白了学算法一定要把算法的原理学透,同时自己也要思考这个算法还有没有其他方法可以实现。

(2)上一节的冒泡排序可以说是我们学习的第一个真正的算法,并且解决了桶排序浪费空间的问题,但是在算法的执行效率上牺牲了很多,它的时间复杂度达到了O(N^2)。那有没有既不浪费空间,又可以快一点的排序算法呢?那就是”快速排序“。

本章的学习目标:

(1)回顾冒泡排序的一个小问题

(2)学习快速排序原理,递归

(3)会用快速排序联系实际生活,解决编程问题

复习冒泡排序时遇到的问题

(1)我们昨天写的冒泡排序是从数组的第1位开始用的,我自己习惯从数组的第0位开始用,所以在我自己编写代码的时候,按照冒泡排序的思路写完编译,我发现有问题。

(2)最后通过自己演算了一遍计算过程,发现从第0位开始写冒泡排序,代码会有点不一样,花时间研究了一遍,这让我更加理解了冒泡排序。

(2)所以说,问题是自己发现的,解决了自己的问题,会掌握得更透彻。

从数组的第0位开始使用数组

#include <stdio.h>
int main()
{int a[100], i, j, t, n;scanf("%d", &n);for (i = 0; i < n; i++)scanf("%d", &a[i]);for(i = 0;i < n - 1;i++){ for (j = 0; j < n - i - 1; j++){if (a[j] > a[j + 1]){t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;}}}for (i = 0; i < n; i++)printf("%d ",a[i]);return 0;
}

对比昨天的代码,从数组的第1位开始使用数组

#include <stdio.h>
int main()
{int a[100], i, j, t, n;scanf("%d", &n);for (i = 1; i <= n; i++)scanf("%d", &a[i]);//冒泡排序的核心部分for (i = 1; i <= n - 1; i++){for (j = 1; j <= n - i; j++){//a[j] > a[j + 1]——从小到大排序;a[j] < a[j + 1]——从大到小排序if (a[j] > a[j + 1])  //若a[j] > a[j + 1],则a[j] 与 a[j + 1]调换位置,即大的放数组后面,故实现从小到大排序{t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;}}}//数组内的数据已排好序,这一步按顺序打印出数组内的数值for (i = 1; i <= n; i++)   //若i = 1; 则i <= n;要加等号printf("%d ", a[i]);return 0;
}

可以发现,冒泡排序的核心部分代码的第三行代码有些不一样。

快速排序

(1)每次排序的时候设置一个基准点,将小于基准点的数全部放到基准点的左边,将大于基准点的数全部放到基准点的右边。这样每次交换的时候就不会像冒泡排序一样只能在相邻的数之间进行交换,交换的距离就大得多了。因此次数就少了,速度自然就提高了。

(2)快速排序之所以比较快,是因为相比冒泡排序,每次交换都是跳跃式的。

(3)当然在最坏的情况下,仍可能是相邻的两个数进行了交换。

(4)因此,快速排序的最差时间复杂度和冒泡排序是一样的,都是O(N^2),它的平均时间复杂度是O(NlogN)。

(5)其实冒泡排序是基于一种叫做“二分”的思想,我们后面还会遇到”二分“的思想。

#include <stdio.h>
/*****************
*a[101]用于存放要排序的数组
* n是要排序的个数
*****************/
int a[101], n;   //全局变量,这两个变量需要在子函数中使用
/*****************
* 函数名:quicksort
* 形参:int left, int right
* 返回值:无
* 作用:快速排序算法
* ************/
void quicksort(int left, int right)  // left一直都是1
{int i, j, t, temp;if (left > right)return;temp = a[left];  //temp中存的就是基准数i = left;j = right;while (i != j)  //相遇后跳出循环{//顺序很重要,要先从右往左找while (a[j] >= temp && i < j)j--;//再从左往右找while (a[i] <= temp && i < j)  i++;//交换两个数再数组中的位置if (i < j)   //当哨兵i和哨兵j没有相遇时{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()
{int i, j, t;//读入数据scanf("%d",&n);for (i = 1; i <= n; i++)scanf("%d",&a[i]);quicksort(1,n);  //快速排序调用//输出排序后的结果for (i = 1; i <= n; i++)printf("%d ",a[i]);return 0;
}

大致思路就是

开始找,找到了就换,换完了再找再换,直到排序结束。

提问,为什么快速排序,要从边开始找元素?

  1. 快速排序我们每次递归要达成的效果是在基准数左侧的数都比基准数小,在基准数右侧的数都比基准数大
  2. 那我们再来看,左右指针是如何运动的:左指针向右运动,直到碰见比基准数大的数停下,右指针向左运动,直到碰见比基准数小的数停下
  3. 问题就出现在这里,我们最后是要把相遇位置处的数和基准位置处的数字相交换,而我们一直都把第一个数字作为我们的基准数(也就是该区域的最左侧),所以我们要保证交换来的数字比基准数要小
  4. 那么只有先进行右指针的运动,才可以保证在相遇处的数字小于基准数。这是一个:一边先动,才相遇的过程。为确保相遇的时候所在数比基准数小,所以,先从右边开始找元素

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/70764.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

极客时间:数据结构与算法之美【学习笔记+思考实践】

本篇是 《极客时间&#xff1a;数据结构与算法之美》课程的学习笔记和带有自己的一些思考实践。原文学习链接如下&#xff1a;https://time.geekbang.org/column/intro/100017301 开篇词 | 从今天起&#xff0c;跨过“数据结构与算法”这道坎01 | 为什么要学习数据结构和算法&a…

java面试题-spring与mybatis框架面试题

spring与mybatis框架面试题 面试官&#xff1a;Spring框架中的单例bean是线程安全的吗&#xff1f; 候选人&#xff1a; 嗯&#xff01; 不是线程安全的&#xff0c;是这样的 当多用户同时请求一个服务时&#xff0c;容器会给每一个请求分配一个线程&#xff0c;这是多个线程会…

Qt6中使用Qt Charts

官方文档&#xff1a;Qt Charts 6.5.2 如果你是使用 CMake 构建的&#xff0c;则应在 CMakeLists.txt 中添加如下两行代码&#xff1a; find_package(Qt6 REQUIRED COMPONENTS Charts)target_link_libraries(mytarget PRIVATE Qt6::Charts) 其中 mytarget 为你的项目名称。一共…

SpringBoot初级开发--服务请求(GET/POST)所有参数的记录管理(8)

服务端在定位错误的时候&#xff0c;有时候要还原现场&#xff0c;这就要把当时的所有入参参数都能记录下来&#xff0c;GET还好说&#xff0c;基本NGINX都会记录。但是POST的请求参数基本不会被记录&#xff0c;这就需要我们通过一些小技巧来记录这些参数&#xff0c;放入日志…

vue打包的基层原理

npm run build 的原理是利用 Vue CLI 的构建工具&#xff0c;根据项目中配置的各种规则&#xff0c;将源代码转换成可在浏览器中运行的静态文件。 npm run build 主要做了以下几个操作&#xff1a; 读取项目配置&#xff1a;根据项目中的配置文件&#xff0c;如 vue.config.js&…

天津web前端培训班 前端是否适合零基础学?

随着HTML 5和ECMAScript 6的正式发布&#xff0c;大量的前端业务逻辑&#xff0c;极大地增加了前端的代码量&#xff0c;前端代码的模块化、按需加载和依赖管理势在必行&#xff0c;因此Web前端越来越被人们重视。 Web前端的就业前景 Web前端开发工程师薪资持续走高&#xff…

Spring MVC实现RESTful

在 Spring MVC 中&#xff0c;我们可以通过 RequestMapping PathVariable 注解的方式&#xff0c;来实现 RESTful 风格的请求。 1. 通过RequestMapping 注解的路径设置 当请求中携带的参数是通过请求路径传递到服务器中时&#xff0c;我们就可以在 RequestMapping 注解的 val…

小红书下一个爆款趋势锁定 | 秋冬种草指南

今夏「多巴胺」风靡全网&#xff0c;现秋日又捎来一股名为「美拉德」的风……俨然一副“新晋顶流”的架势。 如何抓住这一新趋势&#xff1f;本期千瓜将锁定小红书下一个爆款内容——「美拉德」&#xff0c;剖析笔记与底层逻辑&#xff0c;助力品牌洞见先机&#xff0c;运筹布…

uniapp 高度铺满全屏

问题&#xff1a;在有uni-tabbar的情况下&#xff0c;页面铺满剩下的部分 <template><view :style"{height:screenHeightpx}" class"page"></view> </template> <script>export default {data() {return {screenHeight: &q…

长胜证券:主板或以震荡整理为主 结构性行情持续

长胜证券指出&#xff0c;技术面看&#xff0c;沪指3150点上方谨慎看多&#xff0c;缩量横盘整理代表强势&#xff0c;向上打破需市场放量且权重配合&#xff0c;后市若打破并站稳3230点可视为强势回转行情开启&#xff0c;考虑到短期人民币弱势格局&#xff0c;主板或以震动整…

山东企业ITSS认证条件

申请ITSS认证的条件 1、ITSS认证一级升级为定量级应满足以下基本条件&#xff1a; 具有独立的法人资格; 运维服务能力体系已根据运维服务能力成熟度的一级特征和关键指标建立&#xff0c;并已有效运行六个月以上; 能够提供运营和维护服务的管理、人员、资源、技术和流程的有…

【PCL-11】提取平面上层的目标物,剔除平面下层目标物

因项目需求,需提取平面上的物体,不提取平面下的物体,尝试采用超体聚类+LCCP分割的方式,但由于上层点云模型一侧有空洞,导致分割效果不理想。 这里采用pcl::ExtractPolygonalPrismData类,实现平面上物体的提取。 pcl::ExtractPolygonalPrismData类是通过设定处于同一平面模…

力扣(LeetCode)算法_C++——字母异位词分组

给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 输出: [[“bat”],[“nat”,“tan”…

电脑入门: 路由器初学者完全教程

路由器初学者完全教程 本文以Cisco2620为例,讲述了路由器的初始化配置以及远程接入的配置方法,探讨了如何使用内部网络的DHCP服务功能为远程拨入的用户分配地址信息以及路由器常见故障的排除技巧。 (本文假定Cisco2620路由器为提供远…

React三属性之:props

作用 将父组件的参数传递给子组件 父组件 import ./App.css; import React from react; import PropsTest from ./pages/propsTest class App extends React.Component{render(){return(<div><h2>App组件</h2><PropsTest obj{{name:王惊涛,age:27}}>…

基于qt软件的网上聊天室软件

1.服务器: 1).功能: 用于创建一个客户端&#xff0c;通过文本编辑器来获得端口号&#xff0c;根据获得的端口号创建服务器&#xff0c;等待客户端连接 创建成功会提示服务器创建成功 在收到客户端发送的信息时&#xff0c;把这条信息发送给其他所有客户端&#xff0c;实现群…

【Linux-Day9-进程间通信】

进程间通信 前提引入&#xff1a; 我们之前接触过管道 | 将前一个命令的输出结果作为后一个命令的输入 如&#xff1a;ps | grep “sleep” 其实就是将 ps 的结果写入到一个区域&#xff0c;在从这个区域读出目标数据 有名管道 mkfifo 创建管道文件 : mkfifo fifo ->创…

ip_vs 原理解析 (四)hook 后的开始 NF_INET_LOCAL_OUT

NF_INET_LOCAL_OUT 根据优先级依次是 ip_vs_local_reply4&#xff0c;ip_vs_local_request4 | -- ip_vs_local_reply4| -- ip_vs_out| -- ip_vs_fill_iph_skb // 填充 ip 头| -- ip_vs_proto_data_get // 根据 ip 头获取协议对应的 ipvs data| -- pp->conn_out_ge…

python模块之 Motor 异步pymongo

一、介绍 Motor 是一个用于在 Python 中操作 MongoDB 的异步驱动程序。它是基于 asyncio 库构建的&#xff0c;充分利用了异步编程的优势&#xff0c;使得在 Python 中进行 MongoDB 数据库操作更加高效和灵活 异步支持&#xff1a;Motor 使用 asyncio 库提供异步操作的能力。…

单片机采集传感器数据(整形,浮点型)modbus上传

浮点型数据 占两个寄存器&#xff08;四个字节&#xff09; short 整形 占一个寄存器 &#xff08;两个字节&#xff09; 注意&#xff01;&#xff01;&#xff01;&#xff01; stm32 是小端模式&#xff0c;而modbus解析数据是大端模式 所以先发送高字节 如int a16777220…