快速排序、归并排序、基数排序

快速排序

算法思想

图 1-1

即确定一个基准值(一般为数组中间位置的元素,或者自定义),让待排序数组中所有比基准值小的元素放到基准值左边的位置,所有比基准值大的元素放到基准值右边的位置,这样一趟排序下来,基准值左边的元素都比基准值小,基准值右边的元素都会被基准值大,然后在分别对基准值左右两边的数据进行上述操作,最后得到一个有序数组。

快速排序示意图

图 1-2

代码实现

def quick_sort(arr: list, left: int, right: int):l = left  # 数组左边的下标r = right  # 数组右边的下标# 基准值,此处取数组中间位置的元素pivot = arr[(l + r) // 2]while l < r:# 从数组最左边开始,寻找比基准值大或等于基准值的元素# 找到则退出循环,此时 l 位置的元素就是比基准值大的元素while arr[l] < pivot:l += 1# 从数组最右边开始,寻找比基准值小或等于基准值的元素# 找到则退出循环,此时 r 位置的元素就是比基准值小的元素while arr[r] > pivot:r -= 1# 说明数组中的元素已经以基准值为分界点划分为两部分:比基准值大的在一边,小的在另一边# 退出循环,在下一次循环时对基准值左边/右边的数组再以新的基准值进行划分# 直到整个数组有序if l >= r:break# 把上述找到的两个元素交换# 即把比基准值大的元素放到基准值右边,比基准值小的放在基准值左边t = arr[l]arr[l] = arr[r]arr[r] = t# 如果 l == r ,要分别加1 和 减1,否则会在 while l < r 处进入死循环if l == r:l += 1r -= 1if left < r:  # 对基准值左边的数据进行递归,重复上述步骤quick_sort(arr, left, r)if l < right:  # 对基准值右边的数据进行递归,重复上述步骤quick_sort(arr, l, right)arr = [-9, 78, 0, 23, -567, 70]
quick_sort(arr, 0, len(arr) - 1)
print(arr)  # [-567, -9, 0, 23, 70, 78]

归并排序

算法思想

图 2-1

图 2-2

数据的每一次合并过程都是将两个已经有序的数组合并成一个有序数组,遵从相关算法,图2-2的最后一轮合并(第七次合并)如下图:

图 2-3

代码实现

def merge(arr: list, left: int, mid: int, right: int):"""归并排序的合并部分,本质就是将两个有序数组合并为一个有序数组现假设两个有序数组分别为数组A和数组B,这两个有序数组都放在数组arr中,以mid位置为分割,mid是数组A的最后一个元素的位置数组A是图2-3中蓝绿色部分,数组B就是图2-3的粉色部分:param arr: 待排序数组,包含两个待合并的有序数组,两个有序数组以mid为分割点,数组A是arr的左边部分,数组B是arr右边部分,mid也是数组A的最后一个元素的位置:param left: 数组A的第一个元素的下标:param mid: 数组A和数组B起始都是待排序数组中的一部分,mid表示数组A和数组B的中间位置,也就是数组A的最后一个元素:param right: 数组B的最后一个元素的下标:return:如待排序数组为:[8,4,5,7,1,3,6,2],最后将他们分割为八个数组:8,4,5,7,1,3,6,21、然后将这八个数组两两合并:8和4,5和7,1和3,6和2,得到四个数组第一次合并:合并8和4,所以 arr=[8,4,5,7,1,3,6,2], left=0, mid=0, right=1,数组A=[8], 数组B=[4], 将A和B元素按大小放入temp数组, temp最终结果为:[4,8]将temp复制到arr中,arr最终为:[4,8,5,7,1,3,6,2]同理:第二次合并:合并5和7,所以 arr=[4,8,5,7,1,3,6,2], left=2, mid=2, right=3,数组A=[5], 数组B=[7], 将A和B元素按大小放入temp数组, temp最终结果为:[5,7]将temp复制到arr中,arr最终为:[4,8,5,7,1,3,6,2]第三次合并:合并1和3,所以 arr=[4,8,5,7,1,3,6,2], left=4, mid=4, right=5,数组A=[1], 数组B=[3], 将A和B元素按大小放入temp数组, temp最终结果为:[1,3]将temp复制到arr中,arr最终为:[4,8,5,7,1,3,6,2]第四次合并:合并6和2,所以 arr=[4,8,5,7,1,3,6,2], left=6, mid=6, right=7,数组A=[6], 数组B=[2], 将A和B元素按大小放入temp数组, temp最终结果为:[2,6]将temp复制到arr中,arr最终为:[4,8,5,7,1,3,2,6]2、接下来再把四个数组:[4,8]和[5,7], [1,3]和[2,6]再两两合并,得到两个数组第五次合并:合并[4,8]和[5,7],所以 arr=[4,8,5,7,1,3,2,6], left=0, mid=1, right=3,数组A=[4,8], 数组B=[5,7], 将A和B元素按大小放入temp数组, temp最终结果为:[4,5,7,8]将temp复制到arr中,arr最终为:[4,5,7,8,1,3,2,6]第六次合并:合并[1,3]和[2,6],所以 arr=[4,5,7,8,1,3,2,6], left=4, mid=5, right=7,数组A=[1,3], 数组B=[2,6], 将A和B元素按大小放入temp数组, temp最终结果为:[1,2,3,6]将temp复制到arr中,arr最终为:[4,5,7,8,1,2,3,6]3、最后把两个数组:[4,5,7,8]和[1,2,3,6]合并为一个数组,得到归并排序的最终结果第七次合并:合并[4,5,7,8]和[1,2,3,6],所以 arr=[4,5,7,8,1,2,3,6], left=0, mid=3, right=7,数组A=[4,5,7,8], 数组B=[1,2,3,6], 将A和B元素按大小放入temp数组, temp最终结果为:[1,2,3,4,5,6,7,8]将temp复制到arr中,arr最终为:[1,2,3,4,5,6,7,8]"""i = left  # 指向数组A的第一个元素位置j = mid + 1  # 指向数组B的第一个元素位置temp = []  # 临时保存元素的中转数组# t = 0  # 指向中转数组最后一个元素的位置(中转数组初始为空)# 依次遍历数组A和数组B,将两个数组中较小的元素依次放入中转数组temp(此处按从小到大排序)# 直到两个数组中有一个遍历完毕,则退出循环while (i <= mid and j <= right):if arr[i] <= arr[j]:  # 数组A中 i 位置的元素比数组B中 j 位置的元素要小,所以小的放入中转数组temp.append(arr[i])i += 1else:  # 反之,数组B中 j 位置的元素比数组A中 i 位置的元素要小,所以小的放入中转数组temp.append(arr[j])j += 1# 退出循环说明有一个数组遍历结束,将另一个没遍历结束的数组的剩余元素全部添加到中转数组temp中while i <= mid:  # 说明先结束的是数组B,将数组A剩余元素添加到中转数组temptemp.append(arr[i])i += 1while j <= right:  # 说明先结束的是数组A,将数组B剩余元素添加到中转数组temptemp.append(arr[j])j += 1# 将中转数组temp的元素拷贝到数组arrt = 0left_temp = leftwhile left_temp <= right:arr[left_temp] = temp[t]left_temp += 1t += 1def merge_sort(arr: list, left: int, right: int):"""归并排序的分组及合并部分:param arr: 待排序的数组:param left: 已拆分数组的起始位置:param right: 已拆分数组的最后位置:return:"""if left < right:mid = (left + right) // 2merge_sort(arr, left, mid)  # 向左递归merge_sort(arr, mid + 1, right)  # 向右递归merge(arr,left, mid, right)  # 合并sort_arr = [8, 4, 5, 7, 1, 3, 6, 2]
merge_sort(sort_arr, 0, len(sort_arr) - 1)
print(sort_arr)

基数排序

图 3-1

图 3-2

算法思想

图 3-3

代码实现

详细步骤代码
def radix_sort_detail(arr: list):# 假设 arr=[53,3,542,748,14,214]# 定义一个二维数组bucket[][],二维数组中的第一维bucket[]表示一个桶,即每个桶是一个一维数组# 因为有0-9十个数字,所以有十个桶,即二维数组的长度为 10# 每个桶从0开始编号,即名字依次为 0-9# 其中每一个桶用来存储待排序的元素# 因为极端情况下可能每个待排序的元素的位数数字一样(如所有待排序元素的个位数都是0),# 所以每个桶的空间都需要和待排序数组长度一样# 由此可见基数排序是典型的以空间换时间bucket = []# 构造一个具有10行的二维数组for i in range(10):bucket.append([])# 假设 arr=[53,3,542,748,14,214]############### 第一轮排序:根据待排序数组元素的个位数进行 ################ 遍历待排序数组,得到每个元素的个位数,根据个位数对应的数字将该元素放入对应的桶中# 如某个元素的个位数是0,则将该元素放入0号桶,如果是2,则放入2号桶for item in arr:digit = item % 10  # 获取元素的个位数# 根据个位数的值,将元素放入到对应的桶中bucket[digit].append(item)# 将所有元素放入到对应的桶中后# 从第0个桶开始,依次获取每个桶中的所有元素,将元素放入到arr中idx = 0for i in range(len(bucket)):  # i为:0-9if len(bucket[i]) != 0:  # 如果桶中有元素,则遍历该桶获取桶中的每一个元素for item in bucket[i]:arr[idx] = itemidx += 1# 每一轮排序过后,把桶清空bucket[i].clear()print('第一轮:', arr)############### 第二轮排序:根据待排序数组元素的十位数进行 ################ 遍历待排序数组,得到每个元素的十位数,根据十位数对应的数字将该元素放入对应的桶中# 如某个元素的十位数是0,则将该元素放入0号桶,如果是2,则放入2号桶for item in arr:digit = item // 10 % 10  # 获取元素的十位数# 根据百位数的值,将元素放入到对应的桶中bucket[digit].append(item)# 将所有元素放入到对应的桶中后# 从第0个桶开始,依次获取每个桶中的所有元素,将元素放入到arr中idx = 0for i in range(len(bucket)):  # i为:0-9if len(bucket[i]) != 0:  # 如果桶中有元素,则遍历该桶获取桶中的每一个元素for item in bucket[i]:arr[idx] = itemidx += 1# 每一轮排序过后,把桶清空bucket[i].clear()print('第二轮:', arr)############### 第三轮排序:根据待排序数组元素的百位数进行 ################ 遍历待排序数组,得到每个元素的百位数,根据百位数对应的数字将该元素放入对应的桶中# 如某个元素的百位数是0,则将该元素放入0号桶,如果是2,则放入2号桶for item in arr:digit = item // 100 % 10  # 获取元素的百位数# 根据百位数的值,将元素放入到对应的桶中bucket[digit].append(item)# 将所有元素放入到对应的桶中后# 从第0个桶开始,依次获取每个桶中的所有元素,将元素放入到arr中idx = 0for i in range(len(bucket)):  # i为:0-9if len(bucket[i]) != 0:  # 如果桶中有元素,则遍历该桶获取桶中的每一个元素for item in bucket[i]:arr[idx] = itemidx += 1# 每一轮排序过后,把桶清空bucket[i].clear()print('第三轮:', arr)arr = [53, 3, 542, 748, 14, 214]
radix_sort_detail(arr)
print(arr)
完整代码
def radix_sort(arr: list):# 假设 arr=[53,3,542,748,14,214]# 定义一个二维数组bucket[][],二维数组中的第一维bucket[]表示一个桶,即每个桶是一个一维数组# 因为有0-9十个数字,所以有十个桶,即二维数组的长度为 10# 每个桶从0开始编号,即名字依次为 0-9# 其中每一个桶用来存储待排序的元素# 因为极端情况下可能每个待排序的元素的位数数字一样(如所有待排序元素的个位数都是0),# 所以每个桶的空间都需要和待排序数组长度一样# 由此可见基数排序是典型的以空间换时间bucket = []# 构造一个具有10行的二维数组for i in range(10):bucket.append([])# 获取待排序数组中的最大的数,然后获取最大数是几位数# 几位数决定了需要排序多少趟max = 0for item in arr:if max < item:max = item# 获取一个数是几位数的技巧:将数转换成字符串然后求其长度count = len(str(max))num = 0n = 1  # 表示正在获取的位数(个位数、十位数、百位数...)while num < count:# 遍历待排序数组,得到每个元素的每一位数digit,根据digit对应的数字将该元素放入对应的桶中# 如digit=0,则将该元素放入0号桶,如果是2,则放入2号桶for item in arr:digit = item // n % 10  # 依次获取获取元素的个位数、十位数、百位数...# 根据digit的值,将元素放入到对应的桶中bucket[digit].append(item)# 将所有元素放入到对应的桶中后# 从第0个桶开始,依次获取每个桶中的所有元素,将元素放入到arr中idx = 0for i in range(len(bucket)):  # i为:0-9if len(bucket[i]) != 0:  # 如果桶中有元素,则遍历该桶获取桶中的每一个元素for item in bucket[i]:arr[idx] = itemidx += 1# 读取桶中的所有元素后,把桶清空bucket[i].clear()# 从个位数开始,依次向更高位取值num += 1n *= 10arr = [53, 3, 542,2014, 748, 1451, 214, 100]
radix_sort(arr)
print(arr)

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

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

相关文章

iOS——Manager封装网络请求

在之前的项目里&#xff0c;我们都是把网络请求写在viewController的viewDidLoad&#xff0c;而实际中使用的时候并不能这么简单&#xff0c;对于不同的需要&#xff0c;我们需要有不同的网络请求。所以我们可以用单例模式创建一个全局的Manager类&#xff0c;用实例Manager来执…

给课题组师弟师妹的开荒手册(终篇)

0 写在前面 终于&#xff0c;在结束收尾工作后敲下了开荒手册的终篇&#xff0c;自己三年研究生生活过的离理想中的完美还差很多&#xff0c;不过胜在完整&#xff0c;哈哈&#xff0c;小满胜万全嘛。希望以自己不太完美的经历为例&#xff0c;抛我的砖&#xff0c;引师弟师妹…

模块电源(四):可调DC-DC

一、DC-DC典型应用 以DC-DC转换器SCT2432数据手册为例&#xff0c;典型应用电路如下图所示&#xff1a; 其中&#xff0c;输出电压为&#xff1a; &#xff0c; DC-DC转换器中&#xff0c; 反馈电压是指反馈回路中的信号电压&#xff0c;用于控制输出电压与设定电压之间的误差&…

【计算机毕设选题推荐】网络在线考试系统SpringBoot+SSM+Vue

前言&#xff1a;我是IT源码社&#xff0c;从事计算机开发行业数年&#xff0c;专注Java领域&#xff0c;专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 网络在线考试系统 技术栈 SpringBootSSMVueMySQLMaven 文章目录 一、网络在线考试系统-环境…

哈佛教授因果推断力作:《Causal Inference: What If 》pdf下载

因果推断是一项复杂的科学任务&#xff0c;它依赖于多个来源的三角互证和各种方法论方法的应用&#xff0c;是用于解释分析的强大建模工具&#xff0c;同时也是机器学习领域的热门研究方向之一。 今天我要给大家推荐的这本书&#xff0c;正是因果推断领域必读的入门秘籍&#…

windows环境下搭建redis5.x集群

下载windows版本redis5.x redis.windows.conf内容修改如下&#xff1a; # 端口 &#xff08;注意&#xff1a;改为每个文件夹对应的端口&#xff0c;分别为6379、6380、6381、6382、6383、6384&#xff09; port 6379 # 允许创建集群 appendonly yes cluster-enabled…

工控网络协议模糊测试:用peach对modbus协议进行模糊测试

0x00 背景 本人第一次在FB发帖&#xff0c;进入工控安全行业时间不算很长&#xff0c;可能对模糊测试见解出现偏差&#xff0c;请见谅。 在接触工控安全这一段时间内&#xff0c;对于挖掘工控设备的漏洞&#xff0c;必须对工控各种协议有一定的了解&#xff0c;然后对工控协议…

ros学习笔记(1)Mac本地安装虚拟机,安装Ros2环境

Ros与Linux的关系 Ros环境基于Linux系统内核 我们平时用的是Linux发行版&#xff0c;centos&#xff0c;ubuntu等等&#xff0c;机器人就用了ubunut 有时候我们经常会听到ubunue的版本&#xff0c;众多版本中&#xff0c;有一些是长期维护版TLS&#xff0c;有一些是短期维护…

面试算法26:重排链表

问题 给定一个链表&#xff0c;链表中节点的顺序是L0→L1→L2→…→Ln-1→Ln&#xff0c;请问如何重排链表使节点的顺序变成L0→Ln→L1→Ln-1→L2→Ln-2→…&#xff1f; 分析 首先把链表分成前后两半。在示例链表中&#xff0c;前半段链表包含1、2、3这3个节点&#xff0c…

分布式系统部署Redis

文章目录 一、单点问题二、主从模式概念配置主从结构查看主从节点断开从属关系拓扑结构主从复制原理replication复制offset偏移量 全量复制和部分复制全量复制部分复制 实时复制redis主节点无法重启 三、主从哨兵模式哨兵概念监控程序人工恢复自动恢复为什么是哨兵集合使用dock…

数字孪生技术在智慧城市应用的推进建议

&#xff08;一&#xff09;坚持需求牵引&#xff0c;强场景重实效 必须始终坚持以人为本、场景导向、需求牵引&#xff0c;站在供给侧结构性改革的角度&#xff0c;突出以用促建&#xff0c;强调建用并重&#xff0c;真正发挥数字孪生城市应用建设的实效。从构建数字孪生创新…

寻找替代Redmine项目管理工具的常见方案

RedMine是一个非常受欢迎的项目管理工具&#xff0c;但它并不是万能的。随着时间的推移&#xff0c;许多功能和特性可能会发生变化或被取消。因此&#xff0c;有许多其他工具可以成为RedMine的替代品。 以下是六种可能的选择&#xff1a; 1、Zoho Projects&#xff1a; Zoho P…

CLIP和改进工作

CLIP和改进工作 CLIP 改进方向 语义分割 Lseg、GroupViT 目标检测 ViLD、GLIP v1/v2 视频理解 VideoCLIP、CLIP4clip、ActionCLIP 图像生成 VQGAN-CLIP、CLIPasso、CLIP-Draw 多模态下游任务 VL Downstream 其他 prompt enginering&#xff08;CoOp等&#xff09; depthCLIP、…

Excel 插入和提取超链接

构造超链接 HYPERLINK(D1,C1)提取超链接 Sheet页→右键→查看代码Sub link()Dim hl As HyperlinkFor Each hl In ActiveSheet.Hyperlinkshl.Range.Offset(0, 1).Value hl.AddressNext End Sub工具栏→运行→运行子过程→提取所有超链接地址参考&#xff1a; https://blog.cs…

手撕Vue-编译指令数据

经过上一篇的分析&#xff0c;完成了查找指令和模板的功能&#xff0c;接下来就是编译指令的数据了。 所以本章节主要处理的方法则是 buildElement 方法&#xff0c;我们先分析一下我们所拿到的数据在进行编码&#xff0c;这样会更加清晰一些。 我将 name, value 打印出来&…

【Redis】Zset 有序集合命令

目录 命令ZADDZCARDZRANGEZCOUNTZREVRANGEZRANGEBYSCOREZPOPMAXBZPOPMAXZPOPMINBZPOPMINZRANKZREVRANKZSCOREZREMZREMRANGEBYRANKZREMRANGEBYSCOREZINCRBY 命令 ZADD 添加或者更新指定的元素以及关联的分数到zset中&#xff0c;分数应该符合double类型&#xff0c;inf/-inf作为…

JVM八股文

1.JVM的内存结构&#xff1f; 2.OOM是什么&#xff0c;怎么排查&#xff1f; 3.请解释四种引用是什么意思有什么区别&#xff1f; 4.GC的回收算法有哪些&#xff1f; 5.怎么判断对象是否存活&#xff1f; 1.什么是JVM内存结构 jvm将虚拟机分为5大区域&#xff0c;程序计数器、…

计算机网络 | 传输层

计算机网络 | 传输层 计算机网络 | 传输层功能概述UDP协议TCP协议TCP协议的特点TCP报文段TCP连接管理TCP连接的建立TCP连接的释放 TCP可靠传输序号确认重传 TCP流量控制TCP拥塞控制慢开始和拥塞避免快重传和快恢复 第5章总结 参考视频&#xff1a;王道计算机考研 计算机网络 参…

【vim 学习系列文章 10 -- vim 将代码中空格高亮显示方法】

文章目录 vim 高亮空格使用背景如何配置vim 可以自动显示空格呢&#xff1f;vim highlight 命令使用介绍vim 空白行的处理vim match 命令详细介绍 vim 高亮空格使用背景 开发人员在编写代码之后&#xff0c;在review通过之后会将代码推到服务器然后merge&#xff0c;但是有些代…

学习嵌入式系统的推荐步骤:

学习嵌入式系统的推荐步骤&#xff1a; 00001. 选择一款Linux发行版作为主要操作系统&#xff0c;如RedHat、Ubuntu、Fedora等。进入Linux后&#xff0c;使用终端进行任务操作。建议不要使用虚拟机&#xff0c;如有需要可考虑双系统安装。 00002. 00003. 学习C语言、数…