排序算法

排序算法

img

内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序
外部排序:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序

算法的时间复杂度

一个算法花费的时间与算法中语句的执行次数成正比,对算法的时间频度 T ( n ) T(n) T(n) 做如下处理:

  • 忽略常数项
  • 忽略低次项
  • 忽略系数

就得到了算法的时间复杂度 O ( f ( n ) ) O(f(n)) O(f(n)),比如 T ( n ) = 3 n 2 + 7 n + 6 = > O ( n 2 ) T(n)=3n^2 + 7n + 6 => O(n^2) T(n)=3n2+7n+6=>O(n2)

常见的算法时间复杂度由小到大依次为: O ( 1 ) < O ( log ⁡ 2 n ) < O ( n ) < O ( n log ⁡ 2 n ) < O ( n 2 ) < O ( n 3 ) < O ( n k ) < O ( 2 n ) O(1)<O(\log_2n)<O(n)<O(n\log_2n)<O(n^2)<O(n^3)<O(n^k)<O(2^n) O(1)O(log2n)O(n)O(nlog2n)O(n2)O(n3)O(nk)O(2n)

常见的时间复杂度

一个小技巧是记住下面的典型代码结构,就可以快速判断一段代码的时间复杂度。

1.常数阶 O ( 1 ) O(1) O(1)

i = 1
j = 2
i += 1
j += 2
m = i+j

2.对数阶 O ( l o g 2 n ) O(log_2n) O(log2n)

i = 1
n = 10
while(i<n):i = i*2

3.线性阶 O ( n ) O(n) O(n)

n = 10
for i in range(n):j = ij += 1

4.线性对数阶 O ( n l o g N ) O(nlogN) O(nlogN)

n = 10
for i in range(n):j = 1while(j<n):j = j*2 

5.平方阶 O ( n 2 ) O(n^2) O(n2)

n = 10
for i in range(n):for j in range(n):m = i+j

稳定算法

在排序算法中,如果排序前后两个相等的数的相对位置不变,则算法稳定;如若发生变化,则算法不稳定。

冒泡排序

冒泡排序是稳定算法,其时间复杂度为 O ( n 2 ) O(n^2) O(n2)

Python 实现

"""
思路:设想有个指针按位滑动,两两交换
代码实现要点:两个for循环,外层循环控制排序的趟数,内层循环控制比较的次数。每趟过后,比较的次数都应该要减1
如果一趟比较下来没有进行过交换,就说明序列有序,因此要在排序过程中设置一个标志flag判断元素是否进行过交换,从而减少不必要的比较
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)for i in range(len(random_numbers)-1):flag = Falsefor j in range(len(random_numbers)-i-1):if random_numbers[j] > random_numbers[j+1]:flag = Truerandom_numbers[j], random_numbers[j+1] = random_numbers[j+1], random_numbers[j]if flag is False:break
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

选择排序

选择排序是不稳定算法,其时间复杂度为 O ( n 2 ) O(n^2) O(n2)

Python 实现

"""
思路:找到数组中最小的元素,与数组第一位元素交换。当只剩一个数时,则不需要选择了,因此需要n-1趟排序
代码实现要点:两个for循环,外层循环控制排序的趟数,内层循环找到当前趟数的最小值,随后与当前趟数组的第一位元素交换
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)for i in range(len(random_numbers)-1):min_idx = ifor j in range(i+1, len(random_numbers)):if random_numbers[min_idx] > random_numbers[j]:min_idx = jrandom_numbers[i], random_numbers[min_idx] = random_numbers[min_idx], random_numbers[i]
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

插入排序

插入排序是稳定算法,其时间复杂度为 O ( n 2 ) O(n^2) O(n2)

Python 实现

"""
思路:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)for i in range(1, len(random_numbers)):key = random_numbers[i]j = i-1while j >= 0 and key < random_numbers[j]:random_numbers[j+1] = random_numbers[j]j -= 1random_numbers[j+1] = key
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

希尔排序

希尔排序是不稳定算法,其时间复杂度为 O ( n 1.3 ) − O ( n 2 ) O(n^{1.3})-O(n^2) O(n1.3)O(n2),视增量大小而定。

Python 实现

"""
希尔排序也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本
思路:把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止
代码特点:希尔排序会定义一个独特的步长变量gap
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)n = len(random_numbers)
gap = int(n/2)
while gap > 0:for i in range(gap, n):temp = random_numbers[i]j = iwhile j >= gap and random_numbers[j-gap] > temp:random_numbers[j] = random_numbers[j-gap]j -= gaprandom_numbers[j] = tempgap = int(gap/2)
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

快速排序

快速排序是不稳定算法,其时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

Python 实现

"""
快速排序是对冒泡排序的一种改进
思路:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
代码特点:快速排序会定义一个分割数据的轴pivot,使用了分治+递归的思想
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)def quicksort(arr):if len(arr) <= 1:return arrpivot = arr[len(arr) // 2]left = [x for x in arr if x < pivot]middle = [x for x in arr if x == pivot]right = [x for x in arr if x > pivot]return quicksort(left) + middle + quicksort(right)random_numbers = quicksort(random_numbers)
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

归并排序

归并排序是稳定算法,其时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

Python 实现

"""
思路:归并排序采用经典的分治策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)
代码特点:归并排序会创建临时数组,占用额外空间
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)def merge(arr, left_idx, middle_idx, right_idx):n1 = middle_idx - left_idx + 1n2 = right_idx - middle_idxleft_temp_arr = [0] * n1right_temp_arr = [0] * n2for i in range(0, n1):left_temp_arr[i] = arr[left_idx + i]for j in range(0, n2):right_temp_arr[j] = arr[middle_idx + 1 + j]i = 0j = 0k = left_idxwhile i < n1 and j < n2:if left_temp_arr[i] <= right_temp_arr[j]:arr[k] = left_temp_arr[i]i += 1else:arr[k] = right_temp_arr[j]j += 1k += 1while i < n1:arr[k] = left_temp_arr[i]i += 1k += 1while j < n2:arr[k] = right_temp_arr[j]j += 1k += 1def mergesort(arr, left_idx, right_idx):if left_idx < right_idx:middle_idx = int((left_idx + (right_idx - 1)) / 2)mergesort(arr, left_idx, middle_idx)mergesort(arr, middle_idx + 1, right_idx)merge(arr, left_idx, middle_idx, right_idx)mergesort(random_numbers, 0, len(random_numbers)-1)
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

基数排序

基数排序是稳定算法,其时间复杂度为 O ( d ( r + n ) ) O(d(r+n)) O(d(r+n)),d 代表长度,r 代表关键字的基数,n 代表关键字个数。

Python 实现

"""
基数排序是对传统桶排序的扩展,速度很快
基数排序是经典的空间换时间的方式,占用内存很大, 当对海量数据排序时,容易造成OutOfMemoryError
有负数的数组,不用基数排序来进行排序
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)max_num = max(random_numbers)
n = 1
while max_num >= 10 ** n:n += 1i = 0
while i < n:bucket = {}for x in range(10):bucket.setdefault(x, [])for x in random_numbers:radix = int(x / (10 ** i)) % 10bucket[radix].append(x)j = 0for k in range(10):if len(bucket[k]) != 0:for y in bucket[k]:random_numbers[j] = yj += 1i += 1
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

堆排序

堆排序是不稳定算法,其时间复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)

Python 实现

"""
堆有大顶堆、小顶堆之分,大顶堆每一次取出来的值都是最大的,在堆排序中用于升序排列;而小顶堆每一次取出来的值都是最小的,在堆排序中用于降序排列
"""import randomrandom.seed(42)
random_numbers = [random.randint(1, 100) for i in range(20)]
print(random_numbers)def heapify(arr, n, i):largest = ileft = 2 * i + 1right = 2 * i + 2if left < n and arr[largest] < arr[left]:largest = leftif right < n and arr[largest] < arr[right]:largest = rightif largest != i:arr[i], arr[largest] = arr[largest], arr[i]heapify(arr, n, largest)n = len(random_numbers)
for i in range(n - 1, -1, -1):heapify(random_numbers, n, i)for i in range(n - 1, 0, -1):random_numbers[i], random_numbers[0] = random_numbers[0], random_numbers[i]heapify(random_numbers, i, 0)
print(random_numbers)
---------
[82, 15, 4, 95, 36, 32, 29, 18, 95, 14, 87, 95, 70, 12, 76, 55, 5, 4, 12, 28]
[4, 4, 5, 12, 12, 14, 15, 18, 28, 29, 32, 36, 55, 70, 76, 82, 87, 95, 95, 95]

总结
img

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面
  • 内排序:所有排序操作都在内存中完成
  • 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行
  • 时间复杂度:一个算法执行所耗费的时间
  • 空间复杂度:运行完一个程序所需内存的大小
  • n:数据规模
  • k:“桶”的个数
  • In-place:不占用额外内存
  • Out-place:占用额外内存

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

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

相关文章

Unity XR Interaction Toolkit(VR、AR交互工具包)记录安装到开发的流程,以及遇到的常见问题(一)!

提示&#xff1a;文章有错误的地方&#xff0c;还望诸位大神不吝指教&#xff01; 文章目录 前言一、XR Interaction Toolkit是什么&#xff1f;二、跨平台交互三、 AR 功能四、XR Interaction Toolkit的特点五、XR Interaction Toolkit 示例总结 前言 随着VR行业的发展&#…

一文搞懂 Java 基础:新手入门必备

目录 &#x1f4dd; Java基础Java起源第一个Java程序基础语法Java标识符Java变量Java注释Java数据类型Java运算符Java流程控制语句 &#x1f4dd; Java基础 Java起源 Java programming language具有大部分编程语言所共有的一些特征&#xff0c;被特意设计用于互联网的分布式环…

《算法笔记》总结No.10——链表

从第10期破例插叙一期单链表的实现&#xff0c;这个东东相当重要&#xff01;考研的同学也可以看&#xff1a;相较于王道考研的伪码不太相同&#xff0c;专注于可以运行。如果是笔试中的伪码&#xff0c;意思正确即可~ 注&#xff1a;博主之前写过一个版本的顺序表和单链表的C实…

Jolt路线图

1. 引言 a16z crypto团队2024年7月更新了其Jolt路线图&#xff1a; 主要分为3大维度&#xff1a; 1&#xff09;链上验证维度&#xff1a; 1.1&#xff09;Zeromorph&#xff1a;见Aztec Labs团队2023年论文 Zeromorph: Zero-Knowledge Multilinear-Evaluation Proofs from…

视觉巡线小车——STM32+OpenMV

系列文章目录 第一章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;一&#xff09; 第二章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;二&#xff09; 第三章&#xff1a;视觉巡线小车——STM32OpenMV&#xff08;三&#xff09; 第四章&#xff1a;视觉巡…

【过题记录】 7.21

Mad MAD Sum 算法&#xff1a;思维&#xff0c;前缀最大值 模拟一下他的运行过程就会发现&#xff0c;两次之后整个数组就固定了&#xff0c;之后每次都是每个数往后移动一位&#xff0c;可以模拟两次之后计算每个数的存活轮数&#xff0c;计算贡献。 #include<bits/stdc.h…

JavaSE 知识梳理(下)

1.继承 继承是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性 的基础上进行扩展&#xff0c;增加新功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承主要解决的问题是&#xff1a;共性的抽取&#xff0c;实现代码复用&a…

【D3.js in Action 3 精译_018】2.4 向选择集添加元素

当前内容所在位置 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可视化最佳实践&#xff08;下&#xff09;1.4 本章小结 第二章…

【PyTorch】图像二分类项目-部署

【PyTorch】图像二分类项目 【PyTorch】图像二分类项目-部署 在独立于训练脚本的新脚本中部署用于推理的模型&#xff0c;需要构造一个模型类的对象&#xff0c;并将权重加载到模型中。操作流程为&#xff1a;定义模型--加载权重--在验证和测试数据集上部署模型。 import torch…

基于PSO算法优化PID参数的一些问题

目录 前言 Q1&#xff1a;惯性权重ω如何设置比较好&#xff1f;学习因子C1和C2如何设置&#xff1f; Q2&#xff1a;迭代速度边界设定一定能够遍历&#xff08;/覆盖&#xff09;整个PID参数二维空间范围吗&#xff1f;还是说需要与迭代次数相关&#xff1f;迭代次数越高&a…

MATLAB图像处理分析基础(一)

一、引言 MATLAB软件得到许多数字图像处理学生、老师和科研工作者的喜爱&#xff0c;成为数字图像处理领域不可或缺的工具之一&#xff0c;其与其他软件相比有以下诸多显著优点。首先&#xff0c;MATLAB 拥有强大的内置函数库&#xff0c;涵盖了图像读取、显示、处理及分析的全…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(九)-无人机区域地面探测与避让(DAA)

引言 3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 【免费】3GPPTS23.256技术报告-无人机系…

ESP8266模块(2)

实例1 查看附近的WiFi 步骤1&#xff1a;进入AT指令模式 使用USB转串口适配器将ESP8266模块连接到电脑。打开串口终端软件&#xff0c;并设置正确的串口和波特率&#xff08;通常为115200&#xff09;。输入以下命令并按回车确认&#xff1a; AT如果模块响应OK&#xff0c;…

【计算机网络】0 课程主要内容(自顶向下方法,中科大郑烇、杨坚)(待)

1 教学目标 掌握计算机网络 基本概念 工作原理 常用技术 为将来学习、应用和研究计算机网络打下坚实基础 2 课程主要内容 1 计算机网络和互联网2 应用层3 传输层4 网络层&#xff1a;数据平面5 网络层&#xff1a;控制平面6 数据链路层和局域网7 网络安全8 无线和移动网络9 多…

构建gitlab远端服务器(check->build->test->deploy)

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言构建gitlab远端服务器一、步骤一:搭建gitlab的运行服务器【运维】1. 第一步:硬件服务器准备工作(1)选择合适的硬件和操作系统linux(2)安装必…

Learning vtkjs之WarpScalar

过滤器 WarpScalar 介绍 先看一个官方的一句话介绍&#xff1a; vtkWarpScalar - deform geometry with scalar data vtkWarpScalar - 使用标量数据变形几何体 详细介绍 vtkWarpScalar is a filter that modifies point coordinates by moving points along point normals by…

spss数据分析是什么 怎么下载spss

什么是SPSS SPSS是社会统计科学软件包的简称&#xff0c; 其官方全称为IBM SPSS Statistics。SPSS软件包最初由SPSS Inc.于1968年推出&#xff0c;于2009年被IBM收购&#xff0c;主要运用于各领域数据的管理和统计分析。作为世界社会科学数据分析的标准&#xff0c;SPSS操作操作…

C++合作开发项目:美术馆1.0

快乐星空MakerZINCFFO 合作入口&#xff1a;CM工作室 效果图&#xff1a; 代码&#xff1a; &#xff08;还有几个音乐&#xff01;&#xff09; main.cpp #include <bits/stdc.h> #include <windows.h> #include <conio.h> #include <time.h> #in…

《数据结构》--顺序表

C语言语法基础到数据结构与算法&#xff0c;前面已经掌握并具备了扎实的C语言基础&#xff0c;为什么要学习数据结构课程&#xff1f;--我们学完本章就可以实践一个&#xff1a;通讯录项目 简单了解过后&#xff0c;通讯录具备增加、删除、修改、查找联系人等操作。要想实现通…

Python学习笔记—100页Opencv详细讲解教程

目录 1 创建和显示窗口... - 4 - 2 加载显示图片... - 6 - 3 保存图片... - 7 - 4 视频采集... - 8 - 5视频录制... - 11 - 6 控制鼠标... - 12 - 7 TrackBar 控件... - 14 - 8.RGB和BGR颜色空间... - 16 - 9.HSV和HSL和YUV.. - 17 - 10 颜色空间的转化... - 18 - …