排序算法汇总,堆排序,归并排序,冒泡排序,插入排序

作者:Tiny番茄日期:9/30/2025

215.数组中的第K个最大元素

1. 堆排序

复杂度分析:

  • 建堆过程时间复杂度为O(n),堆排序过程时间复杂度为O(nlogn)

实现思路:

  • 堆的排序过程实际上就是一颗完全二叉树,根据你输入的元素对该二叉树进行调整。以最小堆为例子,最终实现的效果就是越靠近根节点(上层节点)的其值越小,越靠近叶子节点(下层节点)的其值越大。
  • 如输入数组为[3,2,1,5,6,4]时,此时这个最小堆二叉树为

Code实现(使用python自带的堆进行实现)

1import heapq
2
3class Solution:
4    def findKthLargest(self, nums: List[int], k: int) -> int:
5
6        queue = []
7
8        for ele in nums:                ### 遍历过程:O(n)时间复杂度
9            heapq.heappush(queue, ele)  ### 排序过程:O(nlogn)时间复杂度
10        
11        result = []
12
13        for _ in range(len(queue)):
14            min_ele = heapq.heappop(queue)
15            result.append(min_ele)
16        
17        return result[-k]

2. 归并排序

复杂度分析:

  • 归并排序是在递归后序位置进行自底向上的排序,会有logn次的“并”,每次“并”的时间复杂度是O(n),所以整体时间复杂度为O(nlogn)

实现思路:

  • 先划分再合并,类似的题目参考23. 合并 K 个升序链表,也是采用归并排序的做法
  • 思路其实就是总-分-总,将大数组切割成小数组,当小数组长度为1时,此时就是最小数组单元。后续对两个最小数组单元进行排序,来得到一个稍微大点的有序数组,如此往复,就不断将多个有序数组进行合并后来得到整个的有序数组。

Code

1
2class Solution:
3    def findKthLargest(self, nums: List[int], k: int) -> int:
4        
5        result = self.merge_sort(nums)
6        return result[-k]
7
8
9    def merge_sort(self, nums):         ### 分割数组
10
11        if len(nums) <= 1:
12            return nums
13
14        middle = len(nums) // 2
15
16        nums_left = nums[:middle]
17        nums_right = nums[middle:]
18
19        left = self.merge_sort(nums_left)
20        right = self.merge_sort(nums_right)
21
22        return self.merge(left, right)      ## 左边和右边数组继续切割,切割完后进行merge操作
23    
24    def merge(self, nums_1, nums_2):    ### 合并数组
25
26        merge = []
27
28        i=j=0
29
30        while i < len(nums_1) and j < len(nums_2):
31            if nums_1[i] <= nums_2[j]:      ## nums_1 此时对比的元素更小
32                merge.append(nums_1[i])
33                i += 1
34            else:                           ## nums_2 此时对比的元素更小        
35                merge.append(nums_2[j])
36                j += 1
37        
38        if i < len(nums_1):
39            merge.extend(nums_1[i:])
40        if j < len(nums_2):
41            merge.extend(nums_2[j:])
42
43        return merge

3. 冒泡排序

复杂度分析:

  • 最坏情况时间复杂度:O(n²),即每一次遍历元素都需要进冒泡; 最好情况时间复杂度:O(n),即每一次遍历时不需要进行冒泡,但需要对每个元素都进行遍历操作。平均情况时间复杂度:O(n²)

实现思路:

  • 两个循环,一个循环对每个元素进行遍历。一个循环进行冒泡操作。
  • 冒泡操作需要当前元素与下一个元素进行对比,如果当前元素 > 下一个元素,则两个元素需要交换。(相邻元素的判断 + 是否需要交换)

为什么第二个循环是length - 1 - i,为什么是length - 1 ,因为是跟下一个元素进行比较,因此这里是为了确保 j + 1不越界。而为什么还要减去 i 是因为每次冒后,后面的元素已经确定了,因此后续在进行冒泡时可以不用再比较这些元素了。如下,第一轮冒泡后最后一个元素已经确定是最大了,因此下一轮冒泡时就不用与最后一个元素进行比较了。

Code

1class Solution:
2    def findKthLargest(self, nums: List[int], k: int) -> int:
3        
4        result = self.bubble_sort(nums)
5        return result[-k]
6
7    def bubble_sort(self, nums):
8
9        if len(nums) <= 1:
10            return nums
11
12        length = len(nums)
13        
14        for i in range(length):             ### 确保每一个元素都经历了冒泡排序
15            swapped = False
16
17            for j in range(length-1-i):     ### 对每一个元素进行冒泡排序
18                if nums[j] > nums[j+1]:     ### 当前元素需要进行冒泡
19                    nums[j], nums[j+1] = nums[j+1], nums[j]
20                    swapped = True          ### 记录有没有经过冒泡,表示当前数组还没排序好
21
22            if not swapped:                 ### 如果swapped为False,表明不再需要进行冒泡了,数组已经排序好了
23                break
24
25        return nums

4. 插入排序

复杂度分析:

  • 时间复杂度上:
    • 最好情况:O(n) - 数组已经有序;最坏情况:O(n²) - 数组逆序,每次都要从头查找插入位置
    • 平均情况:O(n²)

实现思路:

  • 元素在插入到数组时,先与数组的最后一个元素对比,如果比这个元素大,那么就可以直接插入到数组的末尾处。
  • 如果没比最后一个元素大,那就要重头开始进行判断操作,判断从左到右,数组中哪个元素刚好大于这个插入值,那就将插入值插入到这个位置,原本这个位置和这个位置之后的元素都同步右移一位。

Code

1class Solution:
2    def findKthLargest(self, nums: List[int], k: int) -> int:
3        
4        result = self.quick_sort(nums)
5        return result[-k]
6
7    def quick_sort(self, nums):
8
9        if len(nums) <= 1:
10            return nums
11        
12        result = []
13        
14        for i in range(len(nums)):
15            if not result:
16                result.append(nums[i])
17            else:
18                pre_val = result[-1]
19                cur_val = nums[i]
20                if cur_val >= pre_val:
21                    result.append(cur_val)
22                else:
23                    left = 0
24                    while result[left] < cur_val:
25                        left += 1
26                    
27                    result.insert(left, cur_val)            ### 在result数组中的left下标添加cur_val这个元素
28        
29        return result

排序算法汇总,堆排序,归并排序,冒泡排序,插入排序》 是转载文章,点击查看原文


相关推荐


多主机Docker Swarm集群网络拓扑可视化监控方案的部署规范
cpsvps_net10/1/2025

本文将从网络架构设计、监控工具选型、数据采集规范、可视化实现和安全策略五个维度,详细解析符合企业级标准的部署方案,帮助运维团队构建高可用、易维护的集群监控体系。


Mosquitto:MQTT Broker入门与分布式部署最佳实践
老坛程序员10/2/2025

本文介绍了开源MQTT代理服务器Mosquitto的核心特性、安装部署及扩展开发。Mosquitto由Eclipse基金会维护,支持MQTT 3.1/3.1.1/5.0协议,具有轻量高效、支持多种QoS等级、TLS加密等特点。文章详细说明了从GitHub源码编译安装的方法,并演示了基本的订阅发布测试。针对分布式场景,提供了多节点部署方案和Docker集群配置示例。最后介绍了如何开发自定义认证插件,通过数据库实现设备鉴权,包括插件框架设计、认证函数实现等关键技术点。全文为MQTT代理服务器的部署应用和功能扩展


SpringCloudGateway:像快递分拣中心一样的API网关
ccccczy_2025/10/2

实际场景引入 想象一下双十一期间的快递分拣中心。海量包裹(用户请求)从四面八方涌来,如何高效、准确地将它们分发到全国各地的配送站(微服务)?这正是Spring Cloud Gateway要解决的问题——作为微服务架构的“总入口”,它负责接收所有外部请求,并根据规则进行路由、过滤和安全控制。 深度解析:核心组件与代码示例 1. 路由(Route)—— 分拣流水线 路由是网关的基本单元,定义了请求从何而来,到哪里去。就像分拣线上的一条条通道,决定包裹的流向。 // 配置文件方式 gateway:


第2章 三个小工具的编写(2)
班公湖里洗过脚2025/10/2

2.3 PEComp的实现 PEComp是PE文件比较器。功能是按照PE文件格式的数据结构按字段对两个指定的PE文件进行比对,以获取两个PE文件结构中的不相同的信息。在实际应用中,我们可以通过对比病毒感染前后PE文件在相关字段上发生的变化来判断病毒的感染方式,从而确定清理病毒的方法。 2.3.1 编程思路 PEComp的功能是在通用框架pe.asm的基础上,实现两个PE文件的对比,并通过图形界面将不同之处形象地表示出来。编码的大致思路如下: 步骤1 打开要比较的两个文件,分别进行文件的内


ChatGPT From Zero To Hero - LLM学习笔记(一)
ASKED_20192025/10/3

如何训练一个chatGPT from zero to hero,主要来源是Karpathy 大神的视频 一、预训练 (Pretraining) Unsupervised Training — 让模型“学会说话” Step 1: Download and preprocessing the internet 下载并清洗互联网数据 从开放语料抓取:Common Crawl、Wikipedia、Books、GitHub、StackExchange、ArXiv去重、过滤低质量和有害内容保证语料


某大厂库存秒杀的设计与实现总结
360_go_php2025/10/4

​ 在面试中,阿里这类大公司的技术面试中,关于高并发场景下的秒杀系统是一个常见的考察点。秒杀系统的核心目标是在大量用户同时请求某一商品时,如何高效、准确地处理并发请求,避免库存超卖,并确保系统的稳定性。下面将详细介绍阿里库存秒杀系统的实现原理和常用技术。​编辑 1. 秒杀系统的基本需求 秒杀系统需要应对高并发请求,尤其是在商品上线后几秒钟内,可能会有成千上万的请求涌入。系统的设计不仅要保证库存的准确性,还要保证用户体验和系统的高可用性。​编辑 2. 核心问题 高并发请求:如何处理成千上万的并发


Windows 环境下安装 Node.js 和 Vue.js 框架完全指南
做运维的阿瑞2025/10/5

本指南将引导你完成在 Windows 操作系统上安装 Node.js、配置 npm 以及安装 Vue.js 框架的全过程。无论你是前端开发新手还是想要搭建本地开发环境的开发者,这篇文章都将为你提供详细的步骤指导和实用技巧。 文章目录 🎯 1. 整体流程概览📦 2. 环境准备与系统要求2.1 系统要求2.2 预备知识 🔧 3. 安装 Node.js3.1 版本选择策略3.2 下载安装包3.3 图形化安装步骤验证安装 ⚡ 4. npm 包管理器配置与优化4.1 npm 基


JMeter接口测试
鱼鱼说测试2025/10/7

1小时postman接口测试从入门到精通教程 1、创建测试任务 添加线程组,右击测试计划,在快捷菜单单击添加-》线程(用户)-》线程组。设置线程组主要包含三个参数:线程数、Ramp-Up、循环次数。 线程数:设置虚拟用户数。一个虚拟用户占用一个进程或线程。线程数就相当于虚拟用户数。 Ramp-Up:设置的线程数启动时长,单位为秒。如果线程数为100,准备时长为20秒,那么需要20秒启动100个线程,平均每秒启动5个线程。 循环次数:每个线程发送请求的个数。如果线程数为100,


Vue3 响应式核心源码全解析:Dep、Link 与 track/trigger 完整执行机制详解
excel2025/10/8

逐行解读 Vue3 的响应式系统是整个框架的灵魂,它让开发者能够在不显式调用更新的情况下自动响应数据变化。本文将带你深入阅读 Vue3 的核心响应式模块源码,重点讲解 Dep、Link、track、trigger 等关键机制,并用通俗的语言串联其工作流程,让你真正理解 Vue3 响应式系统的运行原理。 一、响应式系统的设计思路 Vue3 的响应式系统基于 依赖收集(track) 与 派发更新(trigger) 两大过程: track:在读取响应式数据时记录依赖,建立「谁依赖了谁」的关系; t


微信小程序开发从零基础到项目发布的全流程实战教程(四)
Terio_my2025/10/10

小程序开发实战课程笔记 第一章:项目初始化与纯净环境搭建 在正式进入开发前,我们需要先创建一个干净的小程序项目环境,以便后续教学不受模板或默认配置干扰。 1.1 创建新项目 操作步骤: 打开 微信开发者工具。点击左上角「+」号或「新建项目」按钮。配置项目信息: 项目名称:demo002项目目录:选择本地存储路径AppID:填写自己的小程序 AppID(可使用测试号)项目类型:选择“小程序”不使用云服务不使用模板 ✅ 提示:务必勾选“不使用模板”,否则会自动引入 pa

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0