数据结构与算法:排序算法的稳定性以及各性能比较python实现
招聘笔试中经常会考到排序算法,在此做一个总结。
一、算法概念
1.排序算法的稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
1.简单选择排序
一趟简单排序的操作为:通过n-i次关键字间的比较,从n-i+1个记录中选出关键字最小的记录,并和第i(1<=i<=n)个记录交换之。
- 时间复杂度:
- 空间复杂度:
- 稳定性:不稳定
#选择排序
def selection_sort(list1):print('selection_sort:')list2 = list1.copy()n = len(list2)for i in range(0, n - 1):min_ = iprint(list2)for j in range(i + 1, n):if list2[j] < list2[min_]:min_ = jlist2[i],list2[min_] = list2[min_],list2[i]print(list2,'\n')
2.冒泡排序
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果他们的顺序(如从大到小、首字母从A到Z)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素已经排序完成。
- 时间复杂度:
- 空间复杂度:
- 稳定性:稳定
#冒泡排序
def bubble_sort(list1):print('bubble_sort:')list2 = list1.copy() n = len(list2)for i in range(0, n - 1):print(list2)for j in range(0, n - i - 1 ):if list2[j] > list2[j+1]:list2[j],list2[j+1] = list2[j+1],list2[j]print(list2,'\n')
3.插入排序
将序列的第一个元素当做已经排序好的序列,然后从后面的第二个元素开始,逐个元素进行插入,直到整个序列有序为止。第i趟操作为:在含有i-1个记录的有序子序列r[1...i-1]中插入一个记录r[i]后,变成含有i个记录的有序子序列r[1..i]。
- 时间复杂度:
- 空间复杂度:
- 稳定性:稳定
#插入排序
def insertion_sort(list1):print('insertion_sort:')list2 = list1.copy()n = len(list2)for i in range(1,n):print(list2)value = list2[i]pos = iwhile pos > 0 and value< list2[pos - 1]:list2[pos] = list2[pos - 1]pos -= 1list2[pos] = valueprint(list2)
4.希尔排序
希尔排序(有时称为“递减递增排序”缩小增量排序 Diminishing Increment Sort)通过将原始列表分解为多个较小的子列表来改进插入排序,每个子列表使用插入排序进行排序。 选择这些子列表的方式是希尔排序的关键。不是将列表拆分为连续项的子列表,希尔排序使用增量i(有时称为 gap
),通过选择 i 个项的所有项来创建子列表。
下图1中显示增量为3得到的子列表。个子列表可以通过插入排序进行排序。完成这些排序后,我们得到如图2所示的列表。虽然这个列表没有完全排序,但发生了很有趣的事情。 通过排序子列表,我们已将项目移动到更接近他们实际所属的位置。
图1-2
图3展示了使用增量为 1 的插入排序; 换句话说,标准插入排序。注意,通过执行之前的子列表排序,我们减少了将列表置于其最终顺序所需的移位操作的总数。对于这种情况,我们只需要四次移位完成该过程。
图3
- 时间复杂度: 当n在某个特定范围内,希尔排序所需的比较和移动次数约为,当时,可以减少到
- 空间复杂度:
- 稳定性:不稳定
#希尔排序
def shell_sort(list1, gap):print('shell_sort')list2 = list1.copy()n = len(list2)sub_n = n//gapfor i in range(gap):
# print(i, list2) for j in range(1, sub_n):pos = j value = list2[pos * gap + i]
# print(value)while pos > 0 and value < list2[(pos - 1) * gap + i]:
# print(list2)
# print(pos, value, list2[(pos - 1) * gap + i])list2[pos*gap+i] = list2[(pos - 1) * gap + i]pos -= 1 list2[pos*gap+i] = valueprint('move:', list2)insertion_sort(list2)
5.堆排序
详细原理介绍请看相关博文:
https://blog.csdn.net/qq_18888869/article/details/88886270
6.归并排序
首先介绍一下分治法(Divide and Conquer)
很多有用的算法结构上是递归的,为了解决一个特定问题,算法一次或多次递归调用其自身以解决若干子问题。这些算法遵循分值的思想。分治法在每层递归时有三个步骤:
- 分解:分解原问题为若干子问题,这些子问题是原问题的规模最小的实例
- 解决:解决这些子问题,递归的求解这些子问题。当子问题规模足够小,就可以直接求解
- 合并:合并这些子问题的解成原问题的解
下面介绍归并排序如何利用分治法解决问题:
考虑我们排序这个数组:[10,23,51,18,4,31,13,5] ,我们递归地将数组进行分解
当数组被完全分隔成只有单个元素的数组时,我们需要把它们合并回去,每次两两合并成一个有序的序列。
python实现:
- 分解:将待排序的n个元素分成各包含n/2个元素的子序列
- 解决:使用归并排序递归排序两个子序列
- 合并:合并两个已经排序的子序列以产生已排序的答案
- 时间复杂度:
- 空间复杂度:
- 稳定性:稳定
#归并排序
def merging_sort(list1, ):list2 = list1.copy()length_list2 = len(list2)if length_list2 <= 1:return list2else:mid = int(length_list2/2)left_list = merging_sort(list2[:mid])right_list = merging_sort(list2[mid:])merged_list = merge_sorted_list(left_list, right_list)return merged_listdef merge_sorted_list(left_list, right_list):left_n = len(left_list)right_n = len(right_list)mergedlist = list()i = j = 0while i < left_n and j < right_n:if left_list[i] < right_list[j]:mergedlist.append(left_list[i])i += 1else:mergedlist.append(right_list[j])j += 1if i < left_n:mergedlist.extend(left_list[i:])if j < right_n:mergedlist.extend(right_list[j:])return mergedlist
7.快速排序
快排(与归并排序一样)也是一种分而治之(divide and conquer)的策略。归并排序把数组递归成只有单个元素的数组,之后再不断两两 合并,最后得到一个有序数组。这里的递归基本条件就是只包含一个元素的数组,当数组只包含一个元素的时候,我们可以认为它本来就是有序的(当然空数组也不用排序)。
快排的工作过程其实比较简单,三步走:
选择基准值 pivot 将数组分成两个子数组:小于基准值的元素和大于基准值的元素。这个过程称之为 partition
对这两个子数组进行快速排序。
合并结果
- 时间复杂度:
- 空间复杂度:
- 稳定性:不稳定
#快速排序
def quick_sort(list2, low, high):print('quick_sort:')
# list2 = list1.copy()if len(list2[low:high+1]) <= 1:return list2else:list2, pivot = partition(list2, low, high)print(list2)quick_sort(list2, low, pivot-1 )quick_sort(list2, pivot+1, high)print(list2)def partition(list2, low, high):
# list2 = list1.copy()pivotkey = list2[low] while low < high:
# print('low, high: {},{}'.format(low, high))while low < high and pivotkey < list2[high]:high -= 1
# print('high:',high)list2[low] = list2[high]while low < high and pivotkey > list2[low]:low += 1
# print('low:', low)list2[high] = list2[low]list2[low] = pivotkeyreturn list2, low
8.基数排序
排序方法 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 | 辅助空间 | 稳定性 | 备注 |
冒泡排序 | O(n2) | O(n) | O(n2) | O(1) | 稳定 | n小时较好 |
简单选择排序 | O(n2) | O(n2) | O(n2) | O(1) | 不稳定 | n小时较好 |
直接插入排序 | O(n2) | O(n) | O(n2) | O(1) | 稳定 | 大部分已排序时较好 |
希尔排序 | O(nlogn)~O(n2) | O(n1.3) | O(n2) | O(1) | 不稳定 | s是所选分组 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(1) | 不稳定 | n大时较好 |
归并排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 稳定 | n大时较好 |
快速排序 | O(nlogn) | O(n) | O(n2) | O(nlogn)~O(n) | 不稳定 | n大时较好 |
github代码:https://github.com/makang101/python-data-structure
参考:
problem-solving-with-algorithms-and-data-structure-using-python 中文版
数据结构(C语言版)严蔚敏
数据结构与算法:排序算法的稳定性以及各性能比较python实现相关推荐
- Java数据结构第一讲-排序算法
常见数据结构和算法实现(排序/查找/数组/链表/栈/队列/树/递归/海量数据处理/图/位图/Java版数据结构) 数据结构和算法作为程序员的基本功,一定得稳扎稳打的学习,我们常见的框架底层就是各类数据 ...
- [ 数据结构 -- 手撕排序算法第三篇 ] 希尔排序
手撕排序算法系列之:希尔排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算法:排序算 ...
- 数据结构的各种排序算法稳定性比较
一.前面有讲到了9种排序算法: 1.简单选择排序 2.堆排序 (1和2是属于选择排序) 3.直接插入排序 4.希尔排序 (3和4属于插入排序,有时把改进后的直接插入排序叫做二分插入) 5.冒泡排序 6 ...
- 数据结构与算法 / 排序算法 / 堆排序
一.定义 借助堆结构实现的排序算法被称为堆排序. 二.过程说明 1.建堆 (1)方法1 原地建堆,对于数组来说,从前往后:对于树来说,从下向上. 将数组的第一个元素作为堆顶,第二个元素做向堆中插入数据 ...
- 数据结构与算法 / 排序算法(3)
一.桶排序(Bucket sort) 1.原理 将要排序的数据分到几个有序的桶里,每个桶里的数据再进行排序.桶内的数据排序完毕之后,再把桶里的数据依次取出,组成的序列就是有序的了. 2.原地排序? 属 ...
- 数据结构-常用的排序算法
总第123篇 好久不见哈,我终于又更新了,惊不惊喜,意不意外,哈哈哈哈.等之后会专门写一篇文章给大家汇报汇报我最近在忙什么呢,今天这篇还是接着之前的数据结构系列继续,主要讲讲数据结构里面常用的几种排序 ...
- 数据结构的六大排序算法详解
文章目录 一.简单排序 1.Comparable接口介绍 2.冒泡排序 3.选择排序 4.插入排序 二.高级排序 1.希尔排序 2.归并排序 3.快速排序 4.排序的稳定性 一.简单排序 在我们的程序 ...
- 数据结构基础和排序算法
数据结构和算法 1. 数据结构 1.1 稀疏数组 这个简单 稀疏数组即二维数组中有大量为0或同一个无效值的时候,将其压缩为只有有效数据的稀疏数组,需要使用时将其读写出来转为二维数组. public c ...
- 数据结构和常用排序算法复杂度
1.顺序表 插入操作时间复杂度 最好O(1),最坏O(n),平均O(n) 移动结点的平均次数n/2 删除操作时间复杂度 最好O(1),最坏O(n),平均O(n) 移动结点的平均次数(n-1)/2 按值 ...
最新文章
- Django REST framework API 指南(12):验证器
- 乌班图linux分辨率不能调,ubuntu不能设置高分辨率问题的解决方法,
- php myadmin utf,phpmyadmin在哪里设置utf_8
- Codeforces Round #383 _python作死系列
- UIControl-IOS开发
- java compliance_java complier compliance level问题引发的思考
- c语言实现shellcode转换工具
- 使用 mod_rewrite 来修改 Confluence 6 的 URLs
- 谁说中国没有林纳斯,中国初代IT宗师的封神榜
- IIS服务器重启三种方法
- Farrago for Mac 1.1.0 音频效果和音乐剪辑工具 破解版下载
- [webpack] Content not from webpack is served from “xxxx“ 并且 http://localhost:8080/ 数据为空解决方案
- ORA-28100 策略函数方案NCSI无效
- python基金筛选_【量化投资工具】抓取沪深股市所有指数关联的公募基金列表(含ETF、增强、分级等)...
- mysql中chr_Chr()和chrb()的含义
- 深入理解计算机系统_3e 第四章家庭作业(部分) CS:APP3e chapter 4 homework
- Java桌面应用程序设计新贵:SWT简介
- Ryu环境搭建(Ubuntu20)
- 名片设计大全:15款创意设计的名片模板
- java 云开发系统_云开发 CloudBase CMS 内容管理系统正式开源啦!
热门文章
- 基于ArcGIS10.0和Oracle10g的空间数据管理平台(C#开发)-数据库设计
- JavaScript通过 new FileReader() 获取图片base64 无组件上传图片
- 多功能时钟电路的设计框图_一种病理组织漂片多功能一体机的设计
- java 对第三方的异常_Java第三方API调用打开文件方法时抛出异常
- Promise.allSettled
- OpenCv: 二维坐标的旋转方程
- 《Java程序设计》 第五周学习总结
- Spring集成Mybatis plus
- css3--文字效果
- EIGRP路由协议的数据库