蓝桥之手撕排序算法——冒泡、选择、插入、快排、归并(Python版)

2024-03-18 19:20

本文主要是介绍蓝桥之手撕排序算法——冒泡、选择、插入、快排、归并(Python版),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1. 排序引言

2. 冒泡排序

2.1 算法思想

2.2 代码实现

 2.3 时空复杂度分析

3. 选择排序

3.1 算法思想

3.2 代码实现

 3.3 时空复杂度分析

4. 插入排序

4.1 算法思想

4.3 代码实现

4.4 时空复杂度分析

5. 快速排序

5.1 算法思想

5.2 代码实现

5.3 时空复杂度分析

6. 归并排序

6.1 算法思想

6.2 代码实现

6.3 时空复杂度分析


1. 排序引言

排序算法是算法竞赛中的第一入门必会的算法,可能在语言里面内置好sort排序函数,但是在排序算法中的很多思想是值得我们去学习的,比如从快速排序里面学会如何进行分治以及递归的实现。

2. 冒泡排序

冒泡排序是学习语言和算法中必会的一种算法,下面就由我来进行冒泡排序的分析与代码实现:

2.1 算法思想

对于一个无序数组,我们从索引0开始往右对比,如果当前数字比后一个数字大,就进行交换

这样每次就可以将最大的放在最右边, 上一次对比的最右边的就不再参与下一次排序

因为有N个数,每一次可以将一个最大数排好序,最后一个数也就定好了,因此只需要N-1次,就能排好完整的序。

我们可以看看以下的图:

其实到这里,冒泡排序算法就已经很明确了,每次冒泡都能求出当前最大的数,并将其放在最右边。

2.2 代码实现

a = [6, 5, 4, 1, 3, 2]
n = len(a)
for i in range(n - 1):for j in range(n - i - 1):if a[j] > a[j + 1]:a[j], a[j + 1] = a[j + 1], a[j]
print(a)

 2.3 时空复杂度分析

时间复杂度:

        每次需要比较进行n - i - 1次,也就是n - 1 、 n - 2 、 n - 3.....1次

        一共要执行n - 1次, 大概估算也就是O(n²)

空间复杂度:

        在原数组上面进行的操作,并没有开辟新的空间,所以为:O(1)

3. 选择排序

3.1 算法思想

每次从左往右开始找,找到最小的,然后与当前的索引的数进行交换,并索引加一

这样就能保证,每次都将最小的数排在最前面了。

3.2 代码实现

a = [6, 5, 4, 1, 3, 2]
n = len(a)
for i in range(n - 1):minn = a[i]index = ifor j in range(i + 1, n):if a[j] < minn:minn = min(minn, a[j])index = ja[i], a[index] = a[index], a[i]
print(a)

 3.3 时空复杂度分析

时间复杂度:

        每一次都要从左往右开始比较,从n - 1 次到1次,也就是n(n - 1) / 2次

        一共要进行n - 1次,所以时间复杂度为:O(n²)

空间复杂度:

        没有开辟额外空间,为:O(1)

4. 插入排序

4.1 算法思想

还是从左往右开始进行排序,当前这个数与前面的每一个数进行比较,如果当前的数比前一个数小,那么就一直往左边走,直到那个数比当前的数大为止。

到当前这个数的时候,前面的数其实已经排序好了,只需要找个合适的位置插入进行就好了。

4.3 代码实现

a = [6, 5, 4, 1, 3, 2 , 10]
n = len(a)
for i in range(1 , n):now = a[i]index = ifor j in range(i - 1 , -1 , -1):if a[j] > now:index = ja[j + 1] = a[j]else:breaka[index] = now
print(a)

4.4 时空复杂度分析

时间复杂度:

        插入排序比选择排序更加优化一点,但是最坏情况都是O(n²)

        但是最好的情况下(已经有序),只需要O(n)就行了

空间复杂度:

        没有开辟额外的数组,O(1)

5. 快速排序

5.1 算法思想

快速排序是基于分治算法实现的

分治:将一个大问题分解为多个小问题,分别解决这些小问题,然后将它们的解合并起来,从而得到大问题的解。通常,分治算法包含三个步骤:分解(Divide)、解决(Conquer)、合并(Combine)。

 要想理解分治,首先得理解什么是递归?

递归:递归是指在解决问题的过程中调用自身的过程。在编程中,递归是一种常见的编程技巧,它通过将问题分解成更小的、类似的子问题来解决复杂的问题。

 这是一个简单的递归函数:

def factorial(n):# 基本情况if n == 0:return 1# 递归情况return n * factorial(n - 1)

不难发现,其实这就是求解阶乘的函数,f(n) = n *  fn(n - 1),直到计算到最底层f(0) = 1 ,也就是0的阶乘,然后再不停地返回值,最终得到n的阶乘

当然,上面不理解的话,我们先可以看一下他的实现逻辑:

 先进行分解,算到最底层之后,又从下面往上面推,最终算出f(4)的结果为24

了解什么是分治和递归之后,我们就可以开始愉快的快速排序啦~

快速排序基本步骤:

  • 在数组中找一个基准值x, 一般是中间那个值
  • 将数组分成两个部分:1. 小于等于x的那部分, 2. 大于x的那部分
  • 对两边递归使用该策略

最重要的步骤其实是将数组分成两个部分:

  • 设置基准值l
  • 存放小于等于基准值的下标为:idx = l + 1
  • 从l + 1到r 遍历
    • 如果当前的a[i]<=l , a[i] , a[idx]互换,并且idx += 1
  • 最后就交换idx - 1和 l (idx是刚好大于l的,所以要-1,因为前面执行过一次idx += 1),就能保证l的左边是小于等于基准值的 , 右边是大于基准值的

5.2 代码实现

a = [6, 5, 4, 1, 3, 2, 10]
n = len(a)def fn(a, l, r):# 基准值为:lidx = l + 1   # 右边的索引for i in range(l + 1, r + 1):# 将小于基准值的方在左边 ,大于基准值的放在右边if a[i] <= a[l]:a[i], a[idx] = a[idx], a[i]idx += 1# 将基准值放在中间a[idx - 1], a[l] = a[l], a[idx - 1]# 返回基准值的位置return idx - 1def quick_sort(a, l, r):if l > r:returnmid = fn(a, l, r)  # 分基准值为l,分成两部分,左边<=mid , 右边>midquick_sort(a, l, mid - 1)   # 对左边处理quick_sort(a, mid + 1, r)   # 对右边处理quick_sort(a, 0, n - 1)
print(a)

5.3 时空复杂度分析

时间复杂度:

        在一般情况下,我们每次需要遍历分成两个部分,需要执行n次,每次都分成两个部分,相比线性时间,每次排序的都少了一半,于是就是Logn次

        总时间复杂度大概在O(n * logn)

空间复杂度:

        每次递归都是一次递归二叉树,消费的栈空间大概在O(logn)

6. 归并排序

6.1 算法思想

归并排序也是基于分治算法来的

只是归并排序是先递归,再进行合并

算法步骤:

  • 先分成两个部分
  • 每部分都处理成有序的
  • 再将两个数组合并起来

6.2 代码实现

a = [6, 5, 4, 1, 3, 2, 10]
n = len(a)def merge(a,b):res = []while len(a) != 0 and len(b)!=0:if a[0] <= b[0]:    # 将小的值先放入resres.append(a.pop(0))else:res.append(b.pop(0))# 将a,b剩下的值放进来res.extend(a)res.extend(b)return resdef merge_sort(a):if len(a) < 2:return amid  = len(a) // 2  # 每次分为两个部分left = merge_sort(a[:mid])   # 对左边处理right = merge_sort(a[mid:])   # 对右边处理return merge(left , right)   # 合并两部分a = merge_sort(a)
print(a)

6.3 时空复杂度分析

时间复杂度:

        归并排序与快速排序是类似的,都是O(n * logn)

空间复杂度:

        归并排序每次都需要开辟一个新空间,所以为O(n)

这篇关于蓝桥之手撕排序算法——冒泡、选择、插入、快排、归并(Python版)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/823384

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Python安装Pandas库的两种方法

《Python安装Pandas库的两种方法》本文介绍了三种安装PythonPandas库的方法,通过cmd命令行安装并解决版本冲突,手动下载whl文件安装,更换国内镜像源加速下载,最后建议用pipli... 目录方法一:cmd命令行执行pip install pandas方法二:找到pandas下载库,然后

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

Python标准库之数据压缩和存档的应用详解

《Python标准库之数据压缩和存档的应用详解》在数据处理与存储领域,压缩和存档是提升效率的关键技术,Python标准库提供了一套完整的工具链,下面小编就来和大家简单介绍一下吧... 目录一、核心模块架构与设计哲学二、关键模块深度解析1.tarfile:专业级归档工具2.zipfile:跨平台归档首选3.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3

Python进行JSON和Excel文件转换处理指南

《Python进行JSON和Excel文件转换处理指南》在数据交换与系统集成中,JSON与Excel是两种极为常见的数据格式,本文将介绍如何使用Python实现将JSON转换为格式化的Excel文件,... 目录将 jsON 导入为格式化 Excel将 Excel 导出为结构化 JSON处理嵌套 JSON:

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统