查找与排序-交换排序

交换排序是基于“比较”和“交换”两种操作来实现的排序方法 。

由于选择“比较”的基准元素不同,可将交换排序分为以下两种:

  • 冒泡排序
  • 快速排序

一、冒泡排序 

1.冒泡排序基本思想 

因为其实现与气泡从水中往上冒的过程类似而得名。      

每一趟的过程都是相邻两个元素比较,若为逆序,则交换两个元素,使关键字较小的元素如气泡一般逐渐往上“漂移”,直至最后冒出“水面”。直到某一趟排序过程中没有交换发生,说明序列已完全有序,排序完成。 

2.算法步骤

假设待排序的n个数据元素存放在数组a中

(1)首先将第一个元素与第二个元素进行比较,若为逆序(a[0]>a[1]),则将两个元素交换,然后比较第二个元素和第三个元素。依次类推,直到第n-1个元素完成比较为止。上述过程称为第一次冒泡排序过程,其结果使得最大的记录被放在了最后一个记录的位置上。    

(2)然后进行第二次冒泡排序过程,对前n-1个记录进行同样的操作,将次大的记录放在第n-1个记录的位置上。    

(3)依此类推,直到某一次冒泡排序过程不再有交换发生,算法结束。

3.冒泡排序算法示例 

例:设待排元素序列为{56,25,70,99,82,10,15,56},请给出冒泡排序法进行排序的过程。 

4.算法代码 

def bubble_sort2(self):data_len = len(self.data)for i in range(data_len-1, 0, -1):  # 获得i号位置的正确值flag = Truefor j in range(0, i):if self.data[j+1].key <= self.data[j].key:             self.data[j], self.data[j + 1] = self.data[j + 1], self.data[j]                flag = Falseif flag:break

flag的作用:

  • 冒泡算法的每一轮都是相邻元素a[0]与a[1], a[1]与a[2], ……比较,若为逆序则交换
  • 只要某一轮发生了元素交换,则flag=False,说明此时整个数组还是无序状态,需要进行下一轮的相邻元素比较与交换
  • 若某一轮相邻元素比较下来没有交换发生,则flag=True,说明此时整个序列已经有序了,以后轮次的比较就不再需要了
  • 最好情况下,序列本身有序,则只需进行一轮比较,无交换

5.算法分析 

(1)空间复杂度:在进行元素交换时,冒泡排序需要一个辅助空间临时存放元素,其空间复杂度为O(1)。        

(2)时间复杂度:最好的情况下,序列本身是有序的。此时只需要一趟遍历进行n-1次相邻元素比较,无需交换操作。          最坏的情况下,初始序列为逆序,此时需要n-1趟遍历,第i趟遍历需要比较n-i次,总共比较n(n-1)/2次。每次比较都需要移动,因为每次移动都要通过辅助空间来进行,故每次移动次数都为3,总共移动次数3n(n-1)/2。所以综合考虑,冒泡排序算法的时间复杂度为O(n2)

(3)其他方面:冒泡排序也可用于链式存储结构的序列排序,如果初始序列无序性强,数据元素多,则移动次数较多,此时不宜采用冒泡排序。        

由于冒泡排序是顺次移动元素,所以不会破坏数值相同元素的初始次序,是一种稳定的排序方法。 

二、快速排序

1.快速排序(划分交换排序)算法思想 

(1)从数列中挑出一个元素,称为“基准”。      

(2)重新排序数列,所有比基准值小的元素摆放在基准前面,所有大于或者等于基准值的元素摆在基准的后面,这个称为划分操作。在这个划分结束之后,该基准就处于数列的中间位置。      (3)递归地把小于基准值元素的子数列大于基准值元素的子数列排序进行上述划分过程。 

快速排序基本思想 

  • 将序列中的某一记录设置为枢轴(pivot),一趟排序将枢轴交换到其最终位置,所有小于枢轴的记录交换到枢轴的左边,所有大于等于枢轴的记录交换到枢轴的右边,这个过程称为一趟划分(partition)。
  • 接下来对左子序列和右子序列分别快速排序,直至被排序子序列长度小于等于1为止。
  • 分而治之思想,对整个序列的排序分解为对左子序列和右子序列的排序,是一种递归排序。

 一趟划分方法

  • 对数组data中low~high范围内的元素进行一趟划分。
  • 一般选取data[low]作为枢轴pivot。
  • 在划分过程中始终保持下图所示的不变式,即pivot之后为小于pivot的区域A,紧接着是大于等于pivot的区域B,后面是i号位置开始的待处理区域。初始时,i=low+1,A和B区域的长度都为0。 
  •  为了维持不变式,如果i号记录大于等于pivot,则i加1,即B区域长度增加1;否则,则将i号记录与B区域的最左记录进行交换。
  • 为了方便交换,记录A、B区域的分界点last_small,设last_small为A区域的最右端位置。交换时,将last_small加1,i号记录与last_small位置记录交换,接着i加1。

 

当i超出high的范围,说明除了pivot之外的所有记录都已归入A区域或B区域,如图所示,此时,只需将pivot与last_small所指记录进行交换,即可达成一趟划分的目标。

 2.快速排序算法举例

例:设待排数据元素序列为{26,67,67,9,6,43,82,10,54},请给出快速排序法进行排序的过程。

3.快速排序代码 

 一趟划分交换的代码

def partition(self, low, high):last_small = lowfor i in range(low + 1, high + 1):if self.data[i] < self.data[low]:last_small = last_small + 1self.swap(last_small, i)self.swap(low, last_small)return last_small
def swap(self, i, j):  # 将i号和j号位置的记录交换self.data[i], self.data[j] = self.data[j], self.data[i]

递归算法和接口方法

def recursive_quickSort(self, low, high):if low < high:self.swap(low,(low+high)//2)pivot_position = self.partition(low, high)self.recursive_quickSort(low, pivot_position - 1)self.recursive_quickSort(pivot_position + 1, high)def quick_sort(self):self.recursive_quickSort(0, len(self.data) - 1)

 4.算法分析

(1)空间复杂度:快速排序是递归程序,每层递归调用过程需要一个栈来存放指针与参数,而快速排序最大递归调用的次数与递归树的深度一致,因此最好的情况下空间复杂度为O(log2n),最坏的情况下为O(n)。      

(2)时间复杂度:平均情况O(n log2n) ,最坏情况,即每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况,比如待排序列已经有序的时候,其递归树为单分支树,这样必须进行n-1趟才能将所有元素定位,快速排序已经蜕化为简单排序的水平,其时间复杂度为O(n2)

    当对较大量数据构成的递增序列进行快速排序,且采用首元素为枢轴,可能发生递归调用栈溢出的错误。        

    为避免出现极端情况,可在进行一次划分之前进行“预处理”,即先对data[low].key、data[high].key和data[(low+high)//2].key进行相互比较,然后取关键字值“三者之中”的记录为枢轴记录。 

    当基准元素选择得当的时候(每次都选择中间元素为基准),每一趟排序都能将元素均匀地分割成两个长度相等的子序列,达到快速排序的最好情况,此时分割次数等于完全二叉树的深度log2n,另外,无论序列如何划分,全部比较次数都接近于n-1次,所以时间复杂度为O(nlog2n)。一般情况下,基准元素是随机分布的,序列分割次数接近于log2n,所以快速排序的平均时间复杂度为O(nlog2n)

(3)其他方面:在所有同数量级的排序方法中,依平均时间复杂度,尤其是初始序列无序性强,数据元素比较多的时候,快速排序是目前性能最好的内部排序方法。在排序过程中需要序列的上下边界,所以不适合链式存储结构排序。由于数据元素移动的时候是不按顺序的,所以快速排序是一种不稳定的排序方法。

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

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

相关文章

基于SpringBoot+Vue+uniapp微信小程序的垃圾分类系统的详细设计和实现(源码+lw+部署文档+讲解等)

项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不是配置文件。Spring Boot 通过自动化配置和约…

Redux (八) 路由React-router、嵌套路由、路由传参、路由懒加载

文章目录 一、React-Router的基本使用1. 安装及基本使用(路由映射配置)2. 路由跳转Link与NavLink3. Navigate导航4. 处理路径不存在的情况 二、嵌套路由三、手动跳转 (类似编程式路由导航)1. 函数式组件2. 类组件实现手动跳转 四、路由传参1. 路径设置占位符(params)2. search传…

Java面试指南:Java基础介绍

这是《Java面试指南》系列的第1篇&#xff0c;本篇主要是介绍Java的一些基础内容&#xff1a; 1、Java语言的起源 2、Java EE、Java SE、Java ME介绍 3、Java语言的特点 4、Java和C的区别和联系&#xff1f; 5、面向对象和面向过程的比较 6、Java面向对象的三大特性&#xff1a…

leetcode30:串联所有单词的字串

给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd","ef"]&#xff0c; 那么 "abcdef…

1. 解读DLT698.45-2017通信规约--预连接响应

国家电网有限公司企业标准&#xff0c;面向对象的用电信息数据交换协议DLT698.45-2017 为提高用电信息采集系统的业务适应性、采集效率、安全性和数据溯源性&#xff0c;规范用电信息数据交换协议的通信架构、数据链路层、应用层、接口类与对象标识&#xff0c;制定本标准。 …

Linux系统:(Linux系统概述与安装)

硬件计算机硬件是指计算机系统中所有物理部件的总称。包括计算机主机、显示器、键盘、鼠标、内存、硬盘、处理器、主板等等。这些硬件部件是计算机系统运行的基础 不管是电脑系统(个人电脑、服务器等)、还是移动端操作系统(手机、平板等)。它的功能就是做为用户和硬件之间的桥梁…

前端求职简历-待补充

当然可以&#xff0c;针对大厂的前端岗位&#xff0c;一个吸引人的简历应该突出你的技术能力、项目经验、教育背景以及任何能体现你学习能力和团队协作能力的证明。以下是一个简历大纲示例&#xff0c;你可以根据自己的实际情况进行调整&#xff1a; 个人信息 姓名联系方式&a…

图文深入介绍oracle资源管理(续)

1. 引言&#xff1a; 本文将承接上篇继续深入介绍oracle资源管理。本文重点介绍如何使用oracle资源管理器管理好DB。 2. 资源管理器&#xff1a; 可以使用图形界面 OEM$或命令行调用 DBMS RESOURCE MANAGER 程序包的过程进行数据库资源管理。 调用资源管理器的先决条件&…

瑞数后缀加密怎么处理

前言&#xff1a; 瑞数我们经常补环境通过&#xff0c;但是遇到瑞数后缀不知道怎么处理 就拿瑞数4来讲 解决方法&#xff1a; &#xff08;1&#xff09;传明文加密参数 一般情况&#xff0c;我们传明文加密参数也能访问 &#xff08;2&#xff09;再补环境基础调用open …

基于stm32的4G模块点灯实验

led模块功能封装 #include "led.h" #include "sys.h"//初始化GPIO函数 void led_init(void) {GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin GPIO_PIN_8 | GPIO_PIN_9;gpio_inits…

排序算法 —— 直接插入排序

目录 1.直接插入排序的思想 2.直接插入排序的实现 实现分析 实现代码 3.直接插入排序的分析 时间复杂度分析 空间复杂度分析 稳定性 1.直接插入排序的思想 直接插入排序的思想就是把待排序的元素按其关键码值的大小依次插入到一个已经排好序的有序序列中&#xff0c…

pycharm调试带参数命令行的程序

点击 run configuration 点击加号&#xff0c;选择python name填写程序名字&#xff0c;script填写程序路径&#xff0c;下一行填写传入的参数 点击apply&#xff0c;再点ok&#xff0c;即可debug 参考&#xff1a; pycharm 调试模式下命令行参数的传递_pycharm debug传参 ya…

项目实战:构建 effet.js 人脸识别交互系统的实战之路

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀构建 effet.js &#x1f4d2;1. 什么是effet.js&#x1f4dc;2. 为什么需要使用effet.js&#x1f4dd;3. effet.js的功能&#x1f4da;4. 使用…

【项目案例】-音乐播放器-Android前端实现-Java后端实现

精品专题&#xff1a; 01.C语言从不挂科到高绩点 https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12753294.html?spm1001.2014.3001.5482 02. SpringBoot详细教程 https://blog.csdn.ne…

HTML之表单设计

1、HTML表单 HTML表单是用于收集用户输入的信息&#xff0c;并将用户输入的内容信息传到后台服务器中。 表单是通过form标签实现。 特别注意&#xff1a;如果一些内容提交后&#xff0c;没有将内容提交给后台服务器&#xff0c;那么需要添加一个name属性&#xff0c;语法&am…

NC 单据模板自定义项 设置参照(自定义参照)

NC 单据模板自定义项 设置参照&#xff08;自定义参照&#xff09; 如图下图&#xff0c;NC 单据模板自定义项 设置参照&#xff1a; 1、选择需要设置参照的自定义字段&#xff0c;选择高级属性页签&#xff0c;在类型设置中&#xff0c;数据类型选择参照信息&#xff0c;即bd…

【热门主题】000004 案例 Vue.js组件开发

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

JavaWeb合集11-Maven高级

十一、Maven高级 1、分模块设计与开发 为什么?将项目按照功能拆分成若干个子模块,方便项目的管理维护、扩展,也方便模块间的相互调用&#xff0c;资源共享。 分模块开发需要先针对模块功能进行设计&#xff0c;再进行编码。不会先将工程开发完毕,然后进行拆分。 实现步骤&…

RabbitMQ下载与配置

安装Erlang Erlang 下载地址如下&#xff1a; https://erlang.org/download/otp_versions_tree.html 安装 RabbitMQ RabbitMQ 下载地址如下&#xff1a; https://www.rabbitmq.com/install-windows.html 查看服务&#xff0c;服务已经正常启动 打开Command Prompt 输入rabb…

bash之基本运算符

一.算术运算符 vim test.sh #!/bin/basha10 b20valexpr $a $b echo "a b : $val"valexpr $a - $b echo "a - b : $val"valexpr $a \* $b echo "a * b : $val"valexpr $b / $a echo "b / a : $val"valexpr $b % $a echo "b % a …