面试准备-排序部分:快速排序、堆排序

ops/2025/2/12 8:24:25/

快速排序

快速排序是一种基于**分治思想(Divide and Conquer)**的算法>排序算法。其核心思想是:

  1. 选择一个基准元素(pivot),通常是数组中的某个元素(如最左/最右元素、中间元素或随机选择)。
  2. 通过**分区(partition)**操作,将小于基准的元素放到基准左侧,大于基准的元素放到基准右侧。
  3. 对左右两个子数组递归地进行快速排序,直到子数组长度为1或0(即已排序)。

快排的时间复杂度取决于基准选择的好坏:

最优情况(O(n log n)):每次都能将数组均匀划分,递归深度为log n,每层的分区操作是 O(n),所以总复杂度是 O(n log n)最坏情况(O(n²)):如果每次选择的基准导致极端不均匀划分(如已排序数组选择最左/最右元素),递归深度达到 O(n),每层 O(n),总复杂度 O(n²)

平均情况(O(n log n)):随机选取基准时,通常能保证 O(n log n) 的复杂度。

快排的空间复杂度:

**原地排序版本(Hoare 版)**的快速排序只需要 O(1) 的额外空间。递归调用栈的空间复杂度为 O(log n)(理想情况)到 O(n)(最坏情况)。

改进措施:采用尾递归优化,可以减少栈的使用深度。

快速排序是不稳定的,因为交换操作可能改变相同元素的相对位置

代码:

def qsort(arr: list, l: int, r: int) -> None:if l >= r:  # 递归终止条件,当子数组长度 ≤ 1 时返回return  # 选择中间元素作为 pivot(基准值)i, j, p = l, r, arr[(l + r) >> 1]# 分区操作while i <= j:# 从左向右找到第一个不小于 pivot 的元素while arr[i] < p: i += 1# 从右向左找到第一个不大于 pivot 的元素while arr[j] > p: j -= 1# 当 i <= j 时,交换两侧的元素if i <= j:arr[i], arr[j] = arr[j], arr[i]  # 交换元素,使得左侧小于 pivot,右侧大于 pivoti += 1  # 左指针右移j -= 1  # 右指针左移# 递归处理左子数组if l < j: qsort(arr, l, j)# 递归处理右子数组if i < r: qsort(arr, i, r)

堆排序

堆排序是一种基于比较的算法>排序算法,利用了堆这种数据结构(通常是二叉堆)来完成排序。堆是一棵完全二叉树,具有以下性质:

  • 最大堆(Max-Heap):父节点的值大于或等于子节点的值。
  • 最小堆(Min-Heap):父节点的值小于或等于子节点的值。

堆排序的步骤:

  1. 构建堆:首先将待排序的数组转换为一个堆。通常构建的是最大堆(对于升序排序),即堆顶元素是数组中最大的元素。
  2. 交换根节点与最后一个元素:将堆顶元素(最大元素)与堆的最后一个元素交换。
  3. 重新调整堆:将新的根节点调整为满足堆的性质,恢复最大堆。
  4. 重复步骤 2 和 3,直到堆的大小减少到 1。

时间复杂度:

  • 构建堆O(n)
  • 调整堆:每次调整堆的时间复杂度是 O(logn),总共需要进行 n 次调整,因此整体时间复杂度为 O(nlogn)

堆排序是 不稳定的排序,可能会改变相同元素的相对顺序。

def heapify(arr:list, n:int, i:int):"""将一个子树调整为最大堆,n是堆的大小,i是当前根节点的索引"""largest = i  # 初始化最大值为根节点left = 2 * i + 1  # 左子节点索引right = 2 * i + 2  # 右子节点索引# 如果左子节点大于根节点if left < n and arr[left] > arr[largest]:largest = left# 如果右子节点大于根节点if right < n and arr[right] > arr[largest]:largest = right# 如果根节点不是最大,交换并递归堆化if largest != i:arr[i], arr[largest] = arr[largest], arr[i]  # 交换heapify(arr, n, largest)  # 递归调整子树def heap_sort(arr):"""堆排序的主函数"""n = len(arr)# 构建最大堆for i in range(n // 2 - 1, -1, -1):heapify(arr, n, i)# 一个个从堆顶取出元素,并重新调整堆for i in range(n - 1, 0, -1):arr[i], arr[0] = arr[0], arr[i]  # 交换堆顶元素和当前末尾元素heapify(arr, i, 0)  # 调整剩余部分为最大堆

http://www.ppmy.cn/ops/157729.html

相关文章

《五福临门》后期鉴赏(三)

许是年后忙了&#xff0c;经常没时间看&#xff0c;一开始未曾发觉 后期剧情有点偏离主题了&#xff0c;于常规似乎不合 从婚恋轻喜剧&#xff0c;后面直接变成了断案剧&#xff08;虽然一开始的剧情也不算婚恋轻喜剧&#xff0c;更多的是斗智斗勇&#xff09; 但是&#xff…

python基础入门:7.3并发编程初探

Python并发编程全面解析&#xff1a;解锁程序性能的新维度 # 并发执行模板 import concurrent.futures import timedef task(n):"""模拟耗时任务"""print(f"开始执行任务 {n}")time.sleep(2 if n % 2 0 else 1)return f"任务 {…

云原生周刊:DeepSeek 颠覆人工智能

开源项目推荐 Ollama Ollama 是一个开源的 AI 工具&#xff0c;旨在为用户提供简单而强大的本地部署语言模型解决方案。它支持直接在本地计算机上运行多个预训练的语言模型&#xff0c;能够提供与云端类似的体验&#xff0c;但无需依赖外部服务器或网络连接。 Ollama 的主要…

Unity-Mirror网络框架-从入门到精通之MultipleMatches示例

文章目录 前言MultipleMatchesLobbyViewRoomViewMatchGUIPlayerGUI总结前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开源网络框架,专为多人…

【MySQL — 数据库基础】深入解析MySQL的聚合查询

1. 聚合查询 1.1 聚合函数 函数说明COUNT ( [DISTINCT] expr)返回查询到的数据的数量( 行数 )SUM ( [DISTINCT] expr)返回查询到的数据的总和&#xff0c;不是数字没有意义AVG ( [DISTINCT] expr)返回查询到的数据的平均值&#xff0c;不是数字没有意义MAX( [DISTINCT] expr)…

安卓开发,底部导航栏

1、创建导航栏图标 使用系统自带的矢量图库文件&#xff0c;鼠标右键点击res->New->Vector Asset 修改 Name , Clip art 和 Color 再创建一个 同样的方法再创建四个按钮 2、添加百分比布局依赖 app\build.gradle.kts 中添加百分比布局依赖&#xff0c;并点击Sync Now …

hi3516cv610用海思arm-v01c02-linux-musleabi-strip工具,对库进行瘦身

hi3516cv610用海思arm-v01c02-linux-musleabi-strip工具&#xff0c;对库进行瘦身 执行 arm-v01c02-linux-musleabi-strip libcrypto.so.1.1 应用该工具&#xff0c;对程序裁剪很实用

如何利用DeepSeek开源模型打造OA系统专属AI助手

利用DeepSeek开源模型打造OA系统专属AI助手&#xff0c;可以显著提升办公效率&#xff0c;增强信息检索和管理能力。 注册与登录DeepSeek平台 访问DeepSeek官网 访问DeepSeek的官方网站DeepSeek。使用电子邮件或手机号码注册账号并登录。 获取API Key 登录DeepSeek平台&am…