招聘笔试中经常会考到排序算法,在此做一个总结。

一、算法概念

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实现相关推荐

  1. Java数据结构第一讲-排序算法

    常见数据结构和算法实现(排序/查找/数组/链表/栈/队列/树/递归/海量数据处理/图/位图/Java版数据结构) 数据结构和算法作为程序员的基本功,一定得稳扎稳打的学习,我们常见的框架底层就是各类数据 ...

  2. [ 数据结构 -- 手撕排序算法第三篇 ] 希尔排序

    手撕排序算法系列之:希尔排序. 从本篇文章开始,我会介绍并分析常见的几种排序,大致包括插入排序,冒泡排序,希尔排序,选择排序,堆排序,快速排序,归并排序等. 大家可以点击此链接阅读其他排序算法:排序算 ...

  3. 数据结构的各种排序算法稳定性比较

    一.前面有讲到了9种排序算法: 1.简单选择排序 2.堆排序 (1和2是属于选择排序) 3.直接插入排序 4.希尔排序 (3和4属于插入排序,有时把改进后的直接插入排序叫做二分插入) 5.冒泡排序 6 ...

  4. 数据结构与算法 / 排序算法 / 堆排序

    一.定义 借助堆结构实现的排序算法被称为堆排序. 二.过程说明 1.建堆 (1)方法1 原地建堆,对于数组来说,从前往后:对于树来说,从下向上. 将数组的第一个元素作为堆顶,第二个元素做向堆中插入数据 ...

  5. 数据结构与算法 / 排序算法(3)

    一.桶排序(Bucket sort) 1.原理 将要排序的数据分到几个有序的桶里,每个桶里的数据再进行排序.桶内的数据排序完毕之后,再把桶里的数据依次取出,组成的序列就是有序的了. 2.原地排序? 属 ...

  6. 数据结构-常用的排序算法

    总第123篇 好久不见哈,我终于又更新了,惊不惊喜,意不意外,哈哈哈哈.等之后会专门写一篇文章给大家汇报汇报我最近在忙什么呢,今天这篇还是接着之前的数据结构系列继续,主要讲讲数据结构里面常用的几种排序 ...

  7. 数据结构的六大排序算法详解

    文章目录 一.简单排序 1.Comparable接口介绍 2.冒泡排序 3.选择排序 4.插入排序 二.高级排序 1.希尔排序 2.归并排序 3.快速排序 4.排序的稳定性 一.简单排序 在我们的程序 ...

  8. 数据结构基础和排序算法

    数据结构和算法 1. 数据结构 1.1 稀疏数组 这个简单 稀疏数组即二维数组中有大量为0或同一个无效值的时候,将其压缩为只有有效数据的稀疏数组,需要使用时将其读写出来转为二维数组. public c ...

  9. 数据结构和常用排序算法复杂度

    1.顺序表 插入操作时间复杂度 最好O(1),最坏O(n),平均O(n) 移动结点的平均次数n/2 删除操作时间复杂度 最好O(1),最坏O(n),平均O(n) 移动结点的平均次数(n-1)/2 按值 ...

最新文章

  1. Django REST framework API 指南(12):验证器
  2. 乌班图linux分辨率不能调,ubuntu不能设置高分辨率问题的解决方法,
  3. php myadmin utf,phpmyadmin在哪里设置utf_8
  4. Codeforces Round #383 _python作死系列
  5. UIControl-IOS开发
  6. java compliance_java complier compliance level问题引发的思考
  7. c语言实现shellcode转换工具
  8. 使用 mod_rewrite 来修改 Confluence 6 的 URLs
  9. 谁说中国没有林纳斯,中国初代IT宗师的封神榜
  10. IIS服务器重启三种方法
  11. Farrago for Mac 1.1.0 音频效果和音乐剪辑工具 破解版下载
  12. [webpack] Content not from webpack is served from “xxxx“ 并且 http://localhost:8080/ 数据为空解决方案
  13. ORA-28100 策略函数方案NCSI无效
  14. python基金筛选_【量化投资工具】抓取沪深股市所有指数关联的公募基金列表(含ETF、增强、分级等)...
  15. mysql中chr_Chr()和chrb()的含义
  16. 深入理解计算机系统_3e 第四章家庭作业(部分) CS:APP3e chapter 4 homework
  17. Java桌面应用程序设计新贵:SWT简介
  18. Ryu环境搭建(Ubuntu20)
  19. 名片设计大全:15款创意设计的名片模板
  20. java 云开发系统_云开发 CloudBase CMS 内容管理系统正式开源啦!

热门文章

  1. 基于ArcGIS10.0和Oracle10g的空间数据管理平台(C#开发)-数据库设计
  2. JavaScript通过 new FileReader() 获取图片base64 无组件上传图片
  3. 多功能时钟电路的设计框图_一种病理组织漂片多功能一体机的设计
  4. java 对第三方的异常_Java第三方API调用打开文件方法时抛出异常
  5. Promise.allSettled
  6. OpenCv: 二维坐标的旋转方程
  7. 《Java程序设计》 第五周学习总结
  8. Spring集成Mybatis plus
  9. css3--文字效果
  10. EIGRP路由协议的数据库