python数据结构《排序专题复习》

目录

常见的三种排序方法

冒泡排序

插入排序

选择排序

其他经典的排序方法

快速排序

堆排序

归并排序

 希尔排序

 不同排序方法的各维度对比


排序方式的稳定性:若两个相同的元素在排序前后的相对位置不发生改变的排序为稳定排序,否则不稳定排序

常见的三种排序方法

以【3,2,2,1,1】为例

冒泡排序

冒泡排序思路:不断地对比相邻的两个元素,将若前面的元素 大于(注意不含等于) 后面的元素,则两个元素进行位置交换。

# 冒泡排序,复杂度为O(n^2)
def bubble_sorted(li:list)->list:for i in range(len(li)):# 第几趟exchanged = False# 这个是为了防止多余的遍历,如果前面的元素已经是排序好的,那就不需要再进行比较了,减少运行时间for j in range(len(li)-1):# 遍历列表元素if li[j] > li[j+1]:li[j],li[j+1] = li[j+1],li[j]exchanged = Trueif not exchanged:return li

第一趟

32(1)2(2)1(1)1(2)
2(1)32(2)1(1)1(2)
2(1)2(2)31(1)1(2)
2(1)2(2)1(1)31(2)
2(1)2(2)1(1)1(2)3

第二趟

第三趟

第四趟  、第五趟、第六趟

可见在经过冒泡排序后,相同元素的相对前后位置没有发生改变 ,因此排序是稳定的。

插入排序

插入排序的思路:从左到右,分为有序区和无序区,每次都是将无序区的第一个元素取出插入到有序区间中。然后从右往左遍历有序区,当遍历的有序元素大于该元素时,有序元素右移一位,继续遍历有序区;直到遍历的有序元素小于等于无序区元素第一个元素时,停止遍历,并且将该元素插入到停止遍历有序元素的后一个位置

# 插入排序,复杂度为O(n^2),思路是从左到右抽取一个元素,将这个元素,与左边邻近的元素比较,若比左边的小,则左边元素右移,
# 若不比左边的小了或者已经到最左边了,则将抽取的元素赋值给原本左边元素
def insert_sorted(li:list)->list:for i in range(1,len(li)):# 趟数,也就是抽牌的顺序,从第一张牌开始抽tmp = li[i]j = i - 1# 左边元素while j >= 0 and li[i] < li[j]:# 若抽取的元素小于邻近左边的元素,则将左边元素右移一格li[j+1] = li[j]j -= 1# 这时候的j已经不满足上述条件了,因此这个j位置上的元素没有移动,而j+1上位置的元素移动了是空的li[j+1] = tmpreturn li
32(1)2(2)1(1)1(2)
2(1)32(2)1(1)1(2)
2(1)2(2)31(1)1(2)
1(1)2(1)2(2)31(2)
1(1)1(2)2(1)2(2)3

可见在经过插入排序后,相同元素的相对前后位置没有发生改变 ,因此排序是稳定的。 

选择排序

选择排序的思路:分为有序区和无序区,每次将无序区的最小元素放在无序区的第一个位置,期间会发生元素的交换

# 选择排序,复杂度为O(n^2),思路是遍历一趟元素后,选择最小的值放在无序区的第一位
def select_sorted(li:list)->list:for i in range(len(li)):min_loc = i# 初始化最小值的位置为第一个for j in range(i+1,len(li)-1):if li[j]<li[min_loc]:li[j],li[min_loc] = li[min_loc],li[j]# 交换元素return li

 第一趟

32(1)2(2)1(1)1(2)
2(1)32(2)1(1)1(2)
2(1)32(2)1(1)1(2)
1(1)32(2)2(1)1(2)

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

 在第一趟的选择排序种,我们可以看到相同元素2(1)和2(2)的相对位置在排序前后发生了变化,因此是不稳定排序

其他经典的排序方法

快速排序

快排的思路:先取序列首元素作为基准值,将序列中小于基准值的元素放在左边,大于基准值的元素放在右边(相等的元素放在任一边均可)。然后以该基准值作为边界,对左右子序列递归进行快速排序即可实现排序

具体步骤:

1)选择序列首元素作为基准值,左指针指向序列首位,右指针指向序列尾部;

2)若右指针的元素值大于基准值,右指针继续左移;否则将右指针指向的元素赋值给左指针;

3)赋值完后,移动左指针,若左指针的元素小于基准值,左指针右移,否则将左指针指向的元素赋值给右指针处;

4)重复2)3)直到左右指针重合,将基准值赋值给重合的位置;

5)对左右子序列递归使用1)-4)步骤,这样就实现了对序列的快速排序,递归终止条件为序列含有1个元素,即left<right这里保证有两个元素的时候进行递归,否则退出

def partition(li:list,left:int,right:int)->int:'''这是根据路飞商城的思路来的将p元素归位的函数:取第一个元素为p元素,移动right,若right指针的值大于P,则right继续往左移动,否则停止移动,将值赋值给left所在的位置;然后再移动left,若left指针的值小于P,则left继续往右移动,否则停止移动,将值赋值给right所在的位置;如此交替移动,直到left=right时,停止,并将P值赋值给left(right):param li: 需要归位的列表:param left: 列表左指针索引,初始值为0:param right: 列表右指针索引,初始值为len(li)-1:return: 返回p归位的索引'''#得到要归位的元素(第一个元素)p = li[left]#当列表有两个元素时,才进行排序while left < right:# 保证有两个元素#这里我们从列表的右边开始进行元素的比较while left < right and p < li[right]: # 至少两个元素并且p元素值小于等于right指针指向的值时,右指针左移right -= 1 # right 左移一步li[left] = li[right] # 不满足上述循环条件时,停止移动right,并且将right上的值赋值给left#右指针停止移动后,开始进行左指针的移动while left < right and p > li[left]:left += 1li[right] = li[left]#当left = right时,说明已经归位了,将p赋值给归位位置li[left] = preturn leftdef quickSorted(li,left,right):'''对列表进行快排:param li: 需要排序的列表:param left: 左索引:param right: 右索引:return: 返回排好序的列表'''if left < right:mid = partition(li, left, right)  # 首先得到第一个归位索引# 对左边列表进行排序quickSorted(li,left,mid-1)# 对右边列表进行排序quickSorted(li,mid + 1,right)

 第一趟

基准值p = 5

54(1)94(2)8
54(1)94(2)8
4(2)4(1)94(2)8
4(2)4(1)998
4(2)4(1)598

 由上面可以看出,在进行一趟排序后,两个4的相对位置发生了改变,因此快速排序是不稳定的

 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

堆排序

堆排序是利用了二叉树的数据结构来实现的,稳定排序

归并排序

归并排序的思路:将两个有序序列利用双指针进行合并

难点:如何将待排序的序列变成两个有序序列,当元素只有一个的时候序列是有序的,这个是比较容易理解的。因此这里利用递归的方式,先将列表拆成一个个单元素列表,然后再一个个元素(有序序列)合并,回溯即可实现排序

'''
归并排序的主要思路:将两个有序的子列表归并为一个有序的大列表
'''#归并函数,假设li是由左右两个有序的子列表组成,假设两个子列表都是从小到大排好序的列表
def merge(li,low,mid,high):''':param li: 由左右两个有序的子列表组成的大列表:param low: 列表的起始索引:param mid: 两个子列表的分解处的索引,这里取前面子列表的最后一个元素的索引为mid:param high: 大列表最后一个索引:return: 从小到大排序的列表'''# 当列表中有两个元素时进行归并操作i = low # 第一个子列表的起始索引j = mid + 1 # 第二个子列表的起始索引比较好了的元素lTmp = [] # 用于保存while i <= mid and j <= high: # 当两个子列表都没有遍历完时if li[i] > li[j]:lTmp.append(li[j])j += 1else:lTmp.append(li[i])i += 1while i <= mid:# 当右列表访问结束后,直接将左列表进行添加lTmp.append(li[i])i += 1while j <= high:lTmp.append(li[j])j += 1li[low:high+1] = lTmp#归并排序
def mergeSorted(li,low,high):''':param li: 列表:param low: 列表起始索引:param high: 列表结束索引:return: '''if low < high: # 保证列表有两个元素mid = (low + high)//2mergeSorted(li,low,mid) # 对左列表进行排序mergeSorted(li,mid+1,high) # 对右列表进行排序merge(li,low,mid,high) # 将排好序的两个列表进行归并

 归并排序是稳定排序方式,因为在进行有序列表的合并时,这里看成左右子序列的合并,只有当左序列中的元素大于右子序列的元素的时候,才会将右子序列的元素添加到列表中,这也就保证了在左右序列中有相等元素时,会先将左序列的元素存放在列表中,然后再将右序列的元素存放在列表中

 希尔排序

希尔排序思路:希尔排序的思路其实和归并排序是类似的,都是利用分治的方法实现,不同的是归并排序是另开一个数组来合并两个有序的序列进而实现序列的排序;而希尔排序则是利用插入的方式将两个子序列合并在一起,在序列原地进行修改

'''
希尔排序:将列表分成多组,对每一组进行插入排序,最后合并在一起,d1=len//2,di=d(i-1)//2,直到di=1,退出
'''def insert_sorted_shell(li:list,gap:int)->list:''':param li: 列表:param gap: 分组的组数和每个元素在大列表中的间隔:return: '''for i in range(gap,len(li)):# 趟数,也就是抽牌的顺序,从第一张牌开始抽tmp = li[i]j = i - gap# 左边元素while j >= 0 and li[i] < li[j]:# 若抽取的元素小于邻近左边的元素,则将左边元素右移一格li[j+gap] = li[j]j -= gap# 这时候的j已经不满足上述条件了,因此这个j位置上的元素没有移动,而j+1上位置的元素移动了是空的li[j+gap] = tmpreturn lidef shellSorted(li):n = len(li)d = n//2while d >= 1:insert_sorted_shell(li,d)d //= 2

注意:快速排序、归并排序的左右索引都是闭区间

 不同排序方法的各维度对比

排序方法冒泡排序插入排序选择排序快速排序归并排序希尔排序
稳定性稳定稳定不稳定不稳定稳定稳定
时间复杂度O(n^2)O(n^2)O(n^2)O(nlgn)O(nlogn)O(n^(3/2) )
空间复杂度O(1)O(1)O(1)O(1)O(n)O(1)

从时间复杂度(性能)上来说,一般选择快速排序,是一种排序比较快的排序方法

从稳定性来说,一般选择的是归并排序

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

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

相关文章

BZOJ2844 albus就是要第一个出场

AC通道&#xff1a;http://www.lydsy.com/JudgeOnline/problem.php?id2844 这题貌似HDU上有一道差不多的题&#xff0c;不过我没做过&#xff0c;也就没管了。 首先讲一个线性基的东西&#xff0c;大概就是这样&#xff1a; 然后就是一个什么性质&#xff1a;S异或起来会出现重…

HTG Explains: Why Linux Doesn’t Need Defragmenting

If you’re a Linux user, you’ve probably heard that you don’t need to defragment your Linux file systems. You’ll also notice that Linux distributions don’t come with disk-defragmenting utilities. But why is that? To understand why Linux file systems d…

Spring AOP 实战运用

Spring AOP 实战 看了上面这么多的理论知识, 不知道大家有没有觉得枯燥哈. 不过不要急, 俗话说理论是实践的基础, 对 Spring AOP 有了基本的理论认识后, 我们来看一下下面几个具体的例子吧.下面的几个例子是我在工作中所遇见的比较常用的 Spring AOP 的使用场景, 我精简了很多有…

大话设计模式之策略模式

第二章&#xff1a;商场促销——策略模式 策略模式的定义:策略模式是一种定义一系列算法的方法&#xff0c;从概念上来看&#xff0c;所有这些算法完成的都是相同的工作&#xff0c;知识实现不同&#xff0c;他可以以相同的方式调用所有的算法&#xff0c;减少了各类算法类与使…

【Python学习】——语言风格(变量赋值、深浅拷贝、for循环陷阱)

目录 1、赋值 2、赋值的分类——引用赋值、值赋值 1) 不可变对象引用赋值——字符串、数值、元组等 2&#xff09;可变对象引用赋值——列表、集合、字典 3&#xff09;可变与不可变对象的引用赋值内部分析 4&#xff09;在py文件中&#xff0c;和作用域有关&#xff0c;如…

判断庄家是否出货

1. 大盘处于强势的时候 日平均线在横盘的时候&#xff0c;缓慢拉升然后急剧下跌 高位盘整的时候 2. 有利好消息发布的时候 因为庄家会利用这个对于散户来说这个买入时机来进行出货操作&#xff0c;可见庄家真是阴险狡诈转载于:https://www.cnblogs.com/dcz1001/p/6115893.html

【深度学习】——常见深度学习模型总结、anchor-free和anchor-based

目录 1、faster rcnn&#xff1a; 2、SSD&#xff1a; 3、YOLOv1: 小结&#xff1a; 拓展&#xff1a;anchor-based和anchor-free anchor 1、faster rcnn&#xff1a; FasterRcnn 算法原理讲解笔记&#xff08;非常详细&#xff09;https://blog.csdn.net/xjtdw/article…

真静态和伪静态的区别

首先肯定的是纯静态和伪静态都是SEO的产物&#xff0c;但纯静态和伪静态还是有很大区别的。 纯静态是生成真实的HTML页面保存到服务器端&#xff0c;用户访问时直接访问这 个HTML页面即可&#xff0c;从而大大的减轻了服务器压力&#xff08;如dedecms就是采用的纯静态&#xf…

非常有趣的Console

console觉醒之路&#xff0c;打印个动画如何&#xff1f; 原文地址: http://www.helloweba.com/view-blog-383.html 批量去掉或替换文本中的换行符&#xff08;notepad、sublime text2&#xff09; 原文地址&#xff1a;http://m.blog.csdn.net/article/details?id43228729 有…

假期实践

第一天 地点:杭州颐高数码城 第一天&#xff0c;我来到了自己家附近的颐高数码城。文三路这边有一个卖数码产品的一条街&#xff0c;这里也是最贴近我专业实践的地方&#xff0c;所以第一天的实践我选择了这里。 2001年开业的颐高数码广场座落于“电子一条街”文三路、学院路口…

3.AngularJS-过滤器

转自&#xff1a;https://www.cnblogs.com/best/p/6225621.html 二、过滤器 使用过滤器格式化数据&#xff0c;变换数据格式&#xff0c;在模板中使用一个插值变量。语法格式如下&#xff1a; {{ express | filter:parameter1:p2:p3… | … | …}} 过滤器分了内置过滤器与自定义…

【深度学习】——训练过程

包含哪些层 训练过程 其实就是yf(x)的求参过程&#xff0c;先给参数一个初始值&#xff0c;然后根据初始函数计算得到预测值&#xff0c;根据预测值和真值计算损失&#xff0c;然后又根据损失函数进行反向传播更新参数&#xff0c;更新参数后&#xff0c;再次计算预测值&#…

thinkphp自定义模板标签(一)

thinkphp内置的foreach和include等模板标签使用是非常方便的&#xff1b;但是内置的那些标签只能满足常用功能&#xff0c;个性化的功能就需要我们自己编写自定义模板标签了&#xff1b;下面就是要讲解如何实现&#xff1b; 示例环境&#xff1a;thinkphp3.2.3 thinkphp的模板标…

【深度学习】——激活函数(sigmoid、tanh、relu、softmax)

目录 激活函数 1、作用 2、常用激活函数 3、衡量激活函数好坏的标准&#xff1a; 4、不同的激活函数 1&#xff09;sigmoid 2&#xff09;tanh函数 3&#xff09;RULE函数和leak-relu函数 4&#xff09;softmax函数 激活函数 1、作用 如果只是线性卷积的话&#xff0c…

【深度学习】——分类损失函数、回归损失函数、交叉熵损失函数、均方差损失函数、损失函数曲线、

目录 代码 回归问题的损失函数 分类问题的损失函数 1、 0-1损失 (zero-one loss) 2、Logistic loss 3、Hinge loss 4、指数损失(Exponential loss) 机器学习的损失函数 Cross Entropy Loss Function&#xff08;交叉熵损失函数&#xff09; 交叉熵优点 Mean Squared E…

【转】应用架构一团糟?如何将单体应用改造为微服务

概述 将单体应用改造为微服务实际上是应用现代化的过程&#xff0c;这是开发者们在过去十年来一直在做的事情&#xff0c;所以已经有一些可以复用的经验。 全部重写是绝对不能用的策略&#xff0c;除非你要集中精力从头构建一个基于微服务的应用。虽然听起来很有吸引力&#xf…

Linux 解决ssh连接慢的问题

备份文件 cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak 编辑文件 vi /etc/ssh/sshd_config 输入/ 查找GSSAPIAuthentication 设置如下 GSSAPIAuthentication no # 是否允许使用基于 GSSAPI 的用户认证。默认值为"no"。仅用于SSH-2 详细解释 输入/ 查找UseDNS …

【Hibernate】Hibernate系列6之HQL查询

HQL查询 6.1、概述 6.2、分页查询 6.3、命名查询 6.4、投影查询-部分字段查询 6.5、报表查询 6.6、迫切左外连接、左外连接 6.7、迫切内连接、内连接 6.8、QBC查询、本地查询 转载于:https://www.cnblogs.com/junneyang/p/5254641.html

【深度学习】——梯度下降优化算法(批量梯度下降、随机梯度下降、小批量梯度下降、Momentum、Adam)

目录 梯度 梯度下降 常用的梯度下降算法&#xff08;BGD&#xff0c;SGD&#xff0c;MBGD&#xff09; 梯度下降的详细算法 算法过程 批量梯度下降法&#xff08;Batch Gradient Descent&#xff09; 随机梯度下降法&#xff08;Stochastic Gradient Descent&#xff09…

双工位机器人 焊接夹具注意事项 o(╯□╰)o

焊接夹具设计注意事项 一套完美的夹具,需要机械设计人员正确的设计思想&#xff0c;良好的配件质量&#xff0c;钳工负责认真的装配质量,卡具在使用中不断的修磨和改进&#xff0c;才会达到好的效果。 本人非机械设计&#xff0c;只是在使用焊接卡具过程中遇到了很多卡具设计上…