排序算法对比总结

前提提要:建议请先阅读以下三篇文章,了解本篇所对比的五种算法的基本思想及代码。

https://blog.ZEEKLOG.net/2301_79932175/article/details/157397676?spm=1001.2014.3001.5501

https://blog.ZEEKLOG.net/2301_79932175/article/details/157652329?spm=1001.2014.3001.5501

https://blog.ZEEKLOG.net/2301_79932175/article/details/157691325?spm=1001.2014.3001.5501

一、算法对比总结表

排序

算法

平均

时间复杂度

最好情况

最坏情况

空间复杂度

是否

稳定

核心思想

冒泡

排序

O(n^{2})O(nO(n^{2})O(1)相邻元素两两比较交换,将最大/小值“冒泡”到一端。

选择

排序

O(n^{2})O(n^{2})O(n^{2})O(1)从未排序部分选出最小(大)元素,放到已排序部分的末尾。

插入

排序

O(n^{2})O(nO(n^{2})O(1)将元素插入到已排序序列的合适位置,类似整理扑克牌。

快速

排序

O(n\log n)O(n\log n)O(n^{2}O(\log n) ~ O(n)分治。选取基准,将数组分为小于和大于基准的两部分,递归排序。

归并

排序

O(n\log n)O(n\log n)O(n\log n)O(n)分治。将数组递归地对半拆分,再将有序子数组合并。

二、详细解析

1、冒泡排序

工作原理

重复遍历列表,比较相邻元素,如果顺序错误就交换。每次遍历会将当前未排序部分的最大元素“冒泡”到最后。

优点

  • 实现简单,代码直观。
  • 是稳定排序。

对于已经基本有序的序列,优化后的版本(设置交换标志flag)可以达到接近O(

n

)的时间复杂度。

缺点

效率低,在数据量大时几乎不可用。

适用场景

小规模数据。

2、选择排序

工作原理

将数组分为“已排序”和“未排序”两部分,每次从“未排序”部分中找到最小(或最大)元素,将其与“未排序”部分的第一个元素交换,从而将其纳入“已排序”部分。

优点

  • 实现简单。
  • 交换次数少,对于交换成本高的数据有一定优势。

缺点

  • 不稳定。

时间复杂度恒为 O(

n^{2}

),与数据初始状态无关,非常低效。

适用场景

数据量小,且对稳定性无要求,同时希望减少交换次数的情况。

3、 插入排序

工作原理

将数组分为“已排序”和“未排序”两部分,每次取出“未排序”部分的第一个元素,在“已排序”部分中从后向前扫描,找到相应位置并插入。

优点

  • 实现简单。
  • 稳定排序。
  • 对于小规模或基本有序的数据集,效率非常高。

缺点

平均和最坏情况仍是 O(

n^{2}

),不适合大规模乱序数据。

适用场景

  • 小数组的排序。
  • 部分有序数组的排序。

4、快速排序

工作原理

  • 分区:从数组中选取一个“基准”元素。
  • 排序:将数组重新排列,所有小于基准的元素放在其前面,所有大于基准的放在后面(等于的放哪边都可以)。此时基准处于其最终位置。
  • 递归:递归地对基准前、后的子数组进行快速排序。

优点

平均性能好,是大多数编程语言标准库的默认排序实现基础。

缺点

  • 不稳定

最坏情况(如数组已有序或逆序,且基准选择不当)下时间复杂度为O(

n^{2}

)。通过随机化选择基准或“三数取中法”可以有效避免。

适用场景

处理随机数据大规模排序。

5、归并排序

工作原理

  • 分割:递归地将数组对半分成两个子数组,直到子数组只有一个元素(自然有序)。
  • 合并:递归地将两个有序的子数组合并成一个大的有序数组。合并过程是算法的关键。

优点

  • 稳定排序。

时间复杂度稳定

n\log n

缺点

对于小规模数据,递归和合并的开销可能使其比优化过的插入排序慢。

适用场景

大规模外部排序。

Read more

vue-router(vue 路由)基本使用指南(二)

vue-router(vue 路由)基本使用指南(二)

文章目录 * 深入使用 * 导航守卫 * 重定向与别名 * history 配置:指定历史模式 * 路由元信息(meta) * 拓展 * 状态管理(Pinia / Vuex) * Pinia / Vuex 介绍 * Vuex vs Pinia * Pinia 基本使用 * Pinia 使用 Cookies 存储 深入使用 导航守卫 导航守卫用于在路由跳转前、跳转后或解析过程中,添加自定义的逻辑处理,例如权限验证。 * to 和 from 是即将进入的目标路由和当前导航正要离开的路由 * next 是一个函数,该函数用于控制路由的跳转。 * next():继续执行路由。 * next(false):中断当前路由,如果浏览器的 URL 改变了,那么 URL 会回到 from

By Ne0inhk
Redis 终极实战宝典:Hash 存数据像对象,List 队列秒级响应,性能优化黑科技全解析!

Redis 终极实战宝典:Hash 存数据像对象,List 队列秒级响应,性能优化黑科技全解析!

文章目录 * **`本篇摘要`** * Redis之哈希(Hash) * **Redis哈希(Hash)操作指令** * **1. 基础键值操作** * **2. 批量操作** * **3. 键值列表与统计** * **4. 数值操作** * **5. 高级遍历** * **应用场景与最佳实践** * **常见问题** * Redis 序列化与数据编码 * Hash 结构的应用与优化 * 为什么储存对应用户信息不选择String而选择Hash呢? * 数据存储的“权衡”与优化思路 * Redis之列表(List) * 上文Hash缺点缺点 * List列表 * List常见指令 * 1. **LPUSH key value1 [value2 ...]** * 2. **RPUSH key value1 [value2 ...]** * 3. **LPOP key [cou

By Ne0inhk

Linux侵入式链表详解

侵入式链表详解 目录 1. 什么是侵入式链表 2. 与传统链表的对比 3. 侵入式链表的优势 4. Linux内核中的实现 5. 核心数据结构 6. 核心操作函数 7. container_of宏详解 8. 使用示例 9. 应用场景 10. 总结 什么是侵入式链表 **侵入式链表(Intrusive Linked List)**是一种特殊的链表实现方式,它的特点是:链表节点直接嵌入到数据结构内部,而不是通过指针指向独立的数据节点。 在侵入式链表中,链表节点(list_head)是数据结构的一个成员,而不是独立存在的。这种设计使得链表操作更加高效,并且不需要额外的内存分配。 核心思想 数据结构包含list_head成员list_head嵌入在数据中通过container_of获取完整数据 与传统链表的对比 传统链表(非侵入式) 传统链表通常采用以下结构: // 传统链表节点结构structlist_

By Ne0inhk
【数据结构与算法】单链表的综合运用:1.合并两个有序链表 2.分割链表 3.环形链表的约瑟夫问题

【数据结构与算法】单链表的综合运用:1.合并两个有序链表 2.分割链表 3.环形链表的约瑟夫问题

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人等方向学习者 ❄️个人专栏:《C语言》《【初阶】数据结构与算法》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、合并两个有序链表 * 1.1题目 * 1.2 算法原理 * 1.3代码 * 二、分割链表 * 2.1题目 * 2.2 算法原理 * 2.3代码 * 三、环形链表的约瑟夫问题 * 3.1题目 * 3.2 算法原理 * 3.3代码 * 总结与每日励志 前言 链表是C语言数据结构的核心内容,也是算法面试的高频考点,其灵活的指针操作与逻辑构建对编程思维要求颇高。本文聚焦链表经典实操题型,从合并有序链表、分割链表到环形链表约瑟夫问题,由浅入深拆解解题思路,

By Ne0inhk