十大排序算法详解-上篇:比较排序算法【python 动态图解】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例

1. 引言

在数据驱动的时代,排序算法无处不在,它们是计算机科学的基石之一。无论是在大数据分析、数据库管理、搜索引擎优化,还是在日常软件开发中,有效的排序都是提高效率和性能的关键。但是,排序不仅仅是将数据元素排列成有序序列那么简单,它是一种基础而强大的数据操作,影响着数据结构的选择和算法设计的整体策略。

为什么排序重要?

排序问题的重要性主要体现在以下几个方面:

  1. 数据检索:在排序的数据集上进行搜索比在未排序的数据集上更高效(比如,二分搜索法的前提是数据已排序)。
  2. 数据结构优化:许多数据结构(如优先队列、搜索树等)在内部使用排序机制来提高各种数据操作的效率。
  3. 信息可视化:在数据分析和科学计算中,排序是数据预处理的重要步骤,有助于识别趋势、异常和模式。
  4. 算法优化:许多更复杂的算法(如集合操作或数据库联接操作)的性能可以通过先对数据进行排序来显著提升。

排序的实际应用

实际应用中,排序算法的选择可能会根据具体情况而有很大差异。例如:

  • 在实时系统中,如交易系统,我们可能更倾向于使用时间复杂度最优的排序算法来保证快速响应。
  • 在处理极大数据集的分布式系统中,如使用Hadoop或Spark的环境,排序算法必须能有效地分布在多个节点上处理。
  • 在有严格内存限制的嵌入式系统中,空间效率也许是选择排序算法的决定性因素。

通过探索各种排序算法的性能特点和适用场景,我们不仅可以对它们的工作原理有一个系统的了解,还可以根据实际需要选择或者设计出最适合的算法。

2. 排序算法的分类

  • 比较类排序:基于比较元素之间的大小关系来进行排序。
  • 非比较类排序:不通过比较来决定元素间的顺序。

3. 常见的排序算法详解

					算法思维导图概览

算法思维导图概览

3.1 冒泡排序 (Bubble Sort)
①工作原理
  1. 遍历列表:从列表的第一个元素开始,比较相邻的两个元素。
  2. 比较和交换:如果一对元素是逆序的(即,左边的元素比右边的元素大),则交换它们的位置。
  3. 重复步骤:遍历整个列表,对每一对相邻元素执行步骤2,重复此过程,每次循环结束时,最大的元素会被放置在其最终位置上。
  4. 终止条件:当遍历列表时没有进行任何交换时,说明列表已经完全排序,此时算法结束。
②案例分析 力扣2

对输入的数组进行冒泡排序,输出排序后的数组

​输入:[74,55,35,79,57,71,81,5,82,1]输出:[1,5,35,55,57,71,74,79,81,82]

内循环(比较与交换):算法从数组的第一个元素开始,比较相邻的元素对 (j, j+1)。如果 j 位置的元素大于 j+1 位置的元素(对于升序排序),则这两个元素的位置会被交换。这一过程一直重复,直到到达数组的末尾。每完成一轮内循环,都能保证这一轮中最大的元素被"冒泡"到其最终位置(即数组的最右端)。

要注意的优化:防止已经排序的重复执行,通过增加一个标志位 flag ,若在某轮「内循环」中未执行任何交换操作,则说明数组已经完成排序,直接返回结果即可。这个在已经排序好的情况下 可以减少不必要的比较

外循环(迭代排序的过程):外循环控制内循环的重复执行,每执行完一次内循环后,排序的范围就减少一个元素(因为每次内循环都会将当前未排序部分的最大元素放到正确的位置)。外循环持续进行,直到整个数组排序完成。
在这里插入图片描述
​​​​​动态图
在这里插入图片描述

③代码示例
def bubble_sort(arr):n = len(arr)for i in range(n):# 标记变量,用于优化检测是否有元素交换swapped = False# 最后的元素已经放置好了,每次迭代可以减少一次for j in range(0, n-i-1):# 从头到尾进行比较,不断交换直到最大的数“冒泡”到最后if arr[j] > arr[j+1]:arr[j], arr[j+1] = arr[j+1], arr[j]swapped = True# 如果在某次遍历中没有数据交换,表示已经完成排序,可以提前退出if not swapped:break

使用冒泡排序算法的示例代码体现了算法的直接性和简洁性,但在处理大数据集时,更高效的算法通常是更好的选择。

④算法分析

时间复杂度

  • 最好情况复杂度:(O(n))。当列表已经完全排序时,只需要进行一次遍历,如果没有发生交换,则排序完成。
  • 平均情况复杂度:(O(n^2))。每个元素都需要与其余的( n-1 )个元素比较,并可能需要交换。
  • 最坏情况复杂度:(O(n^2))。当列表完全逆序时,每个元素都需进行( n-1 )次比较和交换。

空间复杂度

  • 空间复杂度:(O(1))。冒泡排序是原地排序算法,除了原始列表,只需要常数级别的额外空间。
3.2 快速排序 (Quick Sort)

快速排序是由英国计算机科学家托尼·霍尔在1960年代提出的一种高效的排序算法。它使用分治策略来把一个序列分为两个子序列,具有较小的元素和较大的元素。

①工作原理
  1. 选择基准值:在数据集中,选择一个元素作为“基准”(pivot)。
  2. 分区操作:重新排列数据,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归排序:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。

快速排序的效率在于它可以在划分数组的同时进行排序。

②案例分析 力扣912

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

在这里插入图片描述

③代码示例
class Solution:def sortArray(self, nums):"""主函数,调用快速排序函数对数组进行排序:param nums: List[int] 需要排序的整数数组:return: List[int] 排序后的数组"""def quickSort(low, high):"""快速排序的递归函数:param low: int 数组的起始索引:param high: int 数组的结束索引"""if low < high:pi = partition(low, high)quickSort(low, pi - 1)quickSort(pi + 1, high)def partition(low, high):"""对数组进行分区,返回基准点索引:param low: int 分区的起始索引:param high: int 分区的结束索引:return: int 基准点的索引"""pivot = nums[high]  # 选取最后一个元素作为基准i = low - 1  # 小于基准的元素的索引for j in range(low, high):if nums[j] < pivot:i += 1nums[i], nums[j] = nums[j], nums[i]  # 交换元素nums[i+1], nums[high] = nums[high], nums[i+1]  # 将基准元素放到正确位置return i + 1quickSort(0, len(nums) - 1)  # 从整个数组的范围开始排序return nums

快速排序因其优异的平均性能和简单的实现成为了排序算法的首选,尤其是在处理大型数据集时。

④算法分析
  • 时间复杂度
    • 最好情况:(O(n \log n)),通常的情况下是所有排序算法中最快的。
    • 平均情况:(O(n \log n))。
    • 最坏情况:(O(n^2)),当数据已经是正序或者逆序时。
  • 空间复杂度
    • (O(\log n)),主要是递归造成的栈空间的使用。
3.3 归并排序 (Merge Sort)
①工作原理
  1. 分解:递归地把当前序列平均分割成两半。
  2. 解决:递归地解决每个子序列。
  3. 合并:将两个排序好的子序列合并成一个最终的排序序列。
②案例分析 力扣912

继续用力扣(LeetCode)上“912. 排序数组”问题可以使用归并排序解决。由于归并排序效率高并且稳定,特别适用于大数据集排序。
在这里插入图片描述

③代码示例
class Solution:def sortArray(self, nums: List[int]) -> List[int]:# 如果数组长度大于1,则继续分解if len(nums) > 1:# 找到中间索引,进行分割mid = len(nums) // 2# 分割成两个子数组L = nums[:mid]R = nums[mid:]# 递归排序两个子数组self.sortArray(L)self.sortArray(R)i = j = k = 0# 合并两个有序子数组while i < len(L) and j < len(R):if L[i] < R[j]:nums[k] = L[i]i += 1else:nums[k] = R[j]j += 1k += 1# 将剩余的元素复制到原数组中while i < len(L):nums[k] = L[i]i += 1k += 1while j < len(R):nums[k] = R[j]j += 1k += 1# 返回排序后的数组return nums
④算法分析
  • 时间复杂度:归并排序在最好、最坏和平均情况下都具有 (O(n \log n)) 的时间复杂度。
  • 空间复杂度:由于需要与原数组同等长度的存储空间来存储合并后的数组,所以空间复杂度为 (O(n))。
  • 稳定性:归并排序是一种稳定的排序算法,因为合并操作不会改变相同元素之间的相对顺序。

归并排序尤其适合用于链表类型的数据结构,或者大型数据集合中,因为它能够提供稳定且一致的性能。

3.4 堆排序 (Heap Sort)

堆排序是基于堆数据结构的一种比较排序算法。堆是一种近似完全二叉树的结构,且满足堆积性质:即任意节点的值总是不大于(或不小于)其子节点的值。

①工作原理
  1. 建立堆:将给定无序数组构造成一个最大堆(或最小堆)。
  2. 交换元素:将堆顶元素(最大值或最小值)与数组末尾元素交换,并将堆的有效大小减一。
  3. 恢复堆:将新的未排序的堆顶元素调整到合适位置,以重新满足堆的性质。
  4. 重复步骤:重复步骤2和3,直到堆的有效大小为1,此时数组已经排序完成。
②力扣案例分析

在力扣(LeetCode)上,题号为“215. 数组中的第K个最大元素”可以通过堆排序的方式来解决。堆排序非常适合用于解决此类问题,因为它可以在O(N log N)的时间内排序,同时可以在O(N)时间内构建堆,而且堆结构使得它能以O(log N)时间找到最大或最小值。
在这里插入图片描述

③代码示例
class Solution:def sortArray(self, nums: List[int]) -> List[int]:# 建立最大堆def heapify(arr, n, i):largest = il = 2 * i + 1r = 2 * i + 2if l < n and arr[l] > arr[largest]:largest = lif r < n and arr[r] > arr[largest]:largest = rif largest != i:arr[i], arr[largest] = arr[largest], arr[i]heapify(arr, n, largest)# 主函数,调用堆排序n = len(nums)# 建立堆for i in range(n // 2 - 1, -1, -1):heapify(nums, n, i)# 一个个交换元素for i in range(n-1, 0, -1):nums[i], nums[0] = nums[0], nums[i]heapify(nums, i, 0)return nums
④算法分析
  • 时间复杂度:堆排序的时间复杂度为O(N log N),其中N是数组的长度。这是因为建立堆的过程是O(N),而进行N次调整的过程是O(N log N)。
  • 空间复杂度:堆排序是原地排序,不需要额外的存储空间,所以空间复杂度为O(1)。
  • 稳定性:堆排序是不稳定的排序算法,因为在调整堆的过程中,无法保证相同元素的相对顺序不变。

附件

部分动态图片来自:https://github.com/hustcc/JS-Sorting-Algorithm

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

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

相关文章

nginx 配置 SSL 证书实现 https 访问

nginx 配置SSL证书实现https访问 1. SSL 证书简介与获取1.1 SSL 证书介绍1.2 获取 SSL 证书 2. nginx 配置 SSL 文件2.1 SSL 文件放置与配置文件修改2.1.1 文件配置2.1.2 强制 https 访问 2.2 验证配置结果 同步发布在个人笔记 nginx 配置 SSL 证书实现 https 访问 配置好 ngi…

LabVIEW和MES系统的智能化车间数据对接

LabVIEW和MES系统的智能化车间数据对接 随着工业4.0时代的到来&#xff0c;智能制造成为推动制造业高质量发展的重要手段。其中&#xff0c;数字化车间作为智能制造的重要组成部分&#xff0c;其设计与实现至关重要。在数字化车间环境下&#xff0c;如何利用LabVIEW软件与MES系…

求最小公倍数

两种方法 1.直接求 import java.util.Scanner;/*** HJ108 求最小公倍数 - 简单*/ public class HJ108 {public static void main(String[] args) {Scanner sc new Scanner(System.in);while(sc.hasNextInt()){int n1 sc.nextInt();int n2 sc.nextInt();for(int i 1; i &l…

OAuth2、JWT

文章目录 OAuth2JWT OAuth2 官网&#xff1a; https://oauth.net/2/ 在 RFC 6749 中说明 1、资源所有者 resource owner&#xff0c; 如 github 用户 2、客户端/第三方应用 client&#xff0c; 如 支持github 登录的 csdn 3、资源服务器 resource server&#xff0c; 如 4、授…

【高阶数据结构】B树 {B树的概念;B树的实现:节点设计,查找,插入,遍历,删除;B树的性能分析;B+树和B*树;B树的应用}

一、常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff…

Linux系统安全:从面临的攻击和风险到安全加固、安全维护策略(文末有福利)

1. Linux面临的攻击与风险 1.1. Linux系统架构 Linux系统架构解读&#xff1a; 用户之间隔离内核态与用户态之间隔离用户进程一般以低权限用户运行系统服务一般以特权服务运行用户态通过系统调用进入内核态内核对系统资源进行管理和分配 1.2. Linux系统常见安全威胁 1.2.1.…

Qt/C++音视频开发71-指定mjpeg/h264格式采集本地摄像头/存储文件到mp4/设备推流/采集推流

一、前言 用ffmpeg采集本地摄像头&#xff0c;如果不指定格式的话&#xff0c;默认小分辨率比如640x480使用rawvideo格式&#xff0c;大分辨率比如1280x720使用mjpeg格式&#xff0c;当然前提是这个摄像头设备要支持这些格式。目前市面上有一些厂家做的本地设备支持264格式&am…

目标检测——YOLOv7算法解读

论文&#xff1a;YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors (2022.7.6) 作者&#xff1a;Chien-Yao Wang, Alexey Bochkovskiy, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2207.02696 代码&#xff1a;h…

C++_第八周做题总结

id:45 A.Equation(类与对象构造) 题目描述 建立一个类Equation&#xff0c;表达方程ax2bxc0。类中至少包含以下方法&#xff1a; 无参构造&#xff08;abc默认值为1.0、1.0、0&#xff09;与有参构造函数&#xff0c;用于初始化a、b、c的值&#xff1b; set方法&#xff0c;…

VS2019中配置C++ OpenCV 4.5.4完整指南

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的在读研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三…

STM32标准库ADC和DMA知识点总结

目录 前言 一、ADC模数转换器 &#xff08;1&#xff09;AD单通道 &#xff08;2&#xff09;AD多通道 二、DMA原理和应用 &#xff08;1&#xff09;DMA数据转运&#xff08;内存到内存&#xff09; &#xff08;2&#xff09;DMAAD多同道&#xff08;外设到内存&#x…

24深圳杯数学建模挑战赛A题6页初步思路+参考论文+保姆级答疑!!!

问题1:单个残骸的精确位置定位 建立数学模型&#xff0c;分析如果要精准确定空中单个残骸发生音爆时的位置坐标&#xff08;经度、纬度、高程&#xff09;和时间&#xff0c;至少需要布置几台监测设备&#xff1f;假设某火箭一级残骸分离后&#xff0c;在落点附近布置了7台监测…

【热门话题】AI作画算法原理解析

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 AI作画算法原理解析AI作画算法概述基础原理&#xff1a;机器学习与深度学习卷积…

Bentley二次开发教程24-交互式类工具

交互式工具概念简述 本次内容主要涉及到交互式工具的使用&#xff0c;在MicroStation中&#xff0c;超过一半的功能都是以交互式工具的形式而存在的&#xff0c;因此交互式工具在MicroStation二次开发中便显得非常重要。当我们的鼠标或键盘在视图中产生交互操作时&#xff0c;…

黑马微服务课程2

课程地址&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09;_哔哩哔哩_bilibili 课程名称&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java…

《A More Fine-Grained Aspect-Sentiment-Opinion Triplet Extraction Task》阅读笔记

一、论文简介 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;情感分析一直是一个热门的研究主题&#xff0c;它帮助机器理解文本中的情感倾向。随着技术的进步&#xff0c;研究者们不断推动情感分析向更细粒度的方向发展&#xff0c;即从简单的正负情感判断&#…

【VueUse】重新定义状态管理在 Vue 中的体验

在 Vue 生态系统中&#xff0c;状态管理一直是开发者们关注的焦点之一。而随着 VueUse 的出现&#xff0c;我们迎来了一种全新的方式来处理状态管理&#xff0c;它让我们能够以更简单、更灵活的方式来管理应用程序的状态。 在本文中我们将深入探讨 VueUse 中与状态管理相关的内…

StrongSORT——基于DeepSORT,提高多目标跟踪的准确性和鲁棒性

1、概述 1.1 DeepSORT DeepSORT算法是在SORT基础上发展起来的一种多目标跟踪算法。SORT算法结合了目标检测器和跟踪器&#xff0c;其中跟踪器的核心是卡尔曼滤波和匈牙利算法。 卡尔曼滤波用于预测目标在下一帧的位置和状态而匈牙利算法则用于将预测状态与实际检测结果进行最…

SpringCloud基础 Consul的引入

前言 首先是为什么引入consul这个组件 我们知道微服务分为很多个模块,这里模块中相互调用,我使用硬编码的模式是不好的 比如微服务模块需要更新的时候,我们使用硬编码的方式可能需要修改很多个地方 但是使用consul之后,就引入了注册中心,我们只需要将对应的服务注册为节点 这样…

android脱壳第二发:grpc-dumpdex加修复

上一篇我写的dex脱壳&#xff0c;写到银行类型的app的dex修复问题&#xff0c;因为dex中被抽取出来的函数的code_item_off 的偏移所在的内存&#xff0c;不在dex文件范围内&#xff0c;所以需要进行一定的修复&#xff0c;然后就停止了。本来不打算接着搞得&#xff0c;但是写了…