当前位置: 首页 > news >正文

冒泡排序,选择排序,插入排序,归并排序,快速排序五种排序方法

一 冒泡排序

冒泡排序是一种简单的排序算法,工作原理是通过重复交换相邻的元素,将较大的元素“冒泡”到数组的末端。以下是冒泡排序的基本步骤和示例代码:

1 冒泡排序步骤

  • 从数组的开始位置,依次比较相邻的两个元素。
  • 如果前一个元素大于后一个元素,则交换它们。
  • 一轮比较后,最大的元素会被放到数组的最后位置。
  • 重复以上步骤,对剩余的元素继续排序,直到整个数组有序。

2 示例代码

function bubbleSort(arr) {const len = arr.length;for (let i = 0; i < len - 1; i++) {for (let j = 0; j < len - 1 - i; j++) {if (arr[j] > arr[j + 1]) {// 交换[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];}}}return arr;
}// 使用示例
const array = [5, 3, 8, 4, 2];
const sortedArray = bubbleSort(array);
console.log(sortedArray); // 输出: [2, 3, 4, 5, 8]

3 时间复杂度

最坏和平均情况下的时间复杂度是 O(n²),最好情况下(数组已经有序)是 O(n)。

二 选择排序(Selection Sort)

1 原理:

选择排序(Selection Sort)是一种简单直观的排序算法,适合小规模的数据排序。它的基本思想是将待排序的数组分为已排序和未排序两部分,然后不断从未排序部分中选择最小(或最大)的元素,将其放到已排序部分的末尾。

时间复杂度:O(n²)

2 示例代码:

arr= [64, 25, 12, 22, 11]

  1. 第 一次循环
  • 未排序部分:[64, 25, 12, 22, 11]
  • 找到最小值 11,交换 11 和 64
  • 结果:[11, 25, 12, 22, 64]
  1. 第 二次循环
  • 未排序部分:[25, 12, 22, 64]

  • 找到最小值 12,交换 12 和 25

  • 结果:[11, 12, 25, 22, 64]

  1. 第三次循环
  • 未排序部分:[25, 22, 64]
  • 找到最小值 22,交换 22 和 25
  • 结果:[11, 12, 22, 25, 64]
  1. 第四次循环
  • 未排序部分:[25, 64]
  • 找到最小值 25,无需交换
  • 结果:[11, 12, 22, 25, 64]

最后,数组已完全排序。

function selectionSort(arr) {const len = arr.length;for (let i = 0; i < len - 1; i++) {let minIndex = i;for (let j = i + 1; j < len; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}// 交换[arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];}return arr;
}

三. 插入排序(Insertion Sort)

1 原理:

将数组分为已排序和未排序两部分,从未排序部分逐个取出元素,插入到已排序部分的合适位置。

  1. 初始化:将第一个元素视为已排序部分。
  2. 遍历未排序部分:从第二个元素开始,逐个取出未排序部分的元素。
  3. 插入位置:将当前元素与已排序部分的元素进行比较,找到合适的位置进行插入。
  4. 移动元素:将已排序部分的元素向右移动,腾出位置插入当前元素。
  5. 重复:重复步骤2到4,直到所有元素排序完成。

时间复杂度:O(n²)

2 示例代码:

function insertionSort(arr) {const len = arr.length;for (let i = 1; i < len; i++) {const key = arr[i];let j = i - 1;while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j--;}arr[j + 1] = key;}return arr;
}

四. 归并排序(Merge Sort)

1 原理:

采用分治法,将数组分成两半,分别排序后再合并。

  1. 分解:将待排序数组递归地分成两半,直到每个部分只包含一个元素(一个元素本身是有序的)。
  2. 合并:将两个已排序的部分合并成一个更大的已排序部分。
  3. 重复:直到所有部分合并完成。

时间复杂度:O(n log n)

2 示例代码:

function mergeSort(arr) {if (arr.length <= 1) return arr;const mid = Math.floor(arr.length / 2);const left = mergeSort(arr.slice(0, mid));const right = mergeSort(arr.slice(mid));return merge(left, right);
}function merge(left, right) {const result = [];let i = 0, j = 0;while (i < left.length && j < right.length) {if (left[i] < right[j]) {result.push(left[i++]);} else {result.push(right[j++]);}}return result.concat(left.slice(i)).concat(right.slice(j));
}

五. 快速排序(Quick Sort)

1 原理:

选择一个“基准”元素,分区使得比基准小的元素在左边,比基准大的元素在右边,然后递归排序。

  1. 选择基准:从数组中选择一个元素作为基准(pivot)。
  2. 分区:将数组重新排列,使得所有比基准小的元素在基准的左侧,所有比基准大的元素在基准的右侧。
  3. 递归排序:对基准左侧和右侧的子数组递归地应用快速排序。

平均情况下 O(n log n),最坏情况下 O(n²)。

假设我们有数组 [10, 80, 30, 90, 40, 50, 70]:

  • 选择基准:假设选择最后一个元素 70 作为基准。
  • 分区: 将数组重新排列为 [10, 30, 40, 50, 70, 90, 80],此时 70 处于正确位置。
  • 递归排序: 对 [10, 30, 40, 50] 和 [90, 80] 进行快速排序。

继续进行分区和递归,最终得到已排序的数组 [10, 30, 40, 50, 70, 80, 90]。

2 示例代码:

function quickSort(arr) {if (arr.length <= 1) return arr;const pivot = arr[arr.length - 1];const left = [];const right = [];for (let i = 0; i < arr.length - 1; i++) {if (arr[i] < pivot) {left.push(arr[i]);} else {right.push(arr[i]);}}return [...quickSort(left), pivot, ...quickSort(right)];
}

  1. 冒泡排序

通过多次遍历数组,比较并交换相邻元素,简单但效率较低。

优点:

  • 实现简单,易于理解。
  • 适合小规模数据。

缺点:

  • 效率低,时间复杂度为 O(n²)。
  • 在大型数据集上性能不佳。
  1. 选择排序

每次选择未排序部分中的最小元素放到已排序部分,时间复杂度为 O(n²)。

优点:

  • 简单易实现。
  • 不需要额外的存储空间,空间复杂度为 O(1)。

缺点:

  • 时间复杂度为 O(n²),效率较低。
  • 不稳定排序,可能改变相同元素的相对位置。
  1. 插入排序

逐个将元素插入到已排序部分的正确位置,适合小规模数据,时间复杂度为 O(n²)。

优点:

  • 在部分有序数据上表现良好,时间复杂度为 O(n)。
  • 实现简单,适合小规模数据。
  • 稳定排序。

缺点:

  • 最坏情况下时间复杂度为 O(n²)。
  • 对大规模数据不够高效。
  1. 归并排序

采用分治法,将数组分为两半递归排序,然后合并,时间复杂度为 O(n log n)。

优点:

  • 时间复杂度为 O(n log n),效率较高。
  • 稳定排序,适合处理大量数据。

缺点:

  • 需要额外的存储空间,空间复杂度为 O(n)。
  • 实现较复杂。
  1. 快速排序

选择基准元素,将数组分为小于和大于基准的两部分,递归排序,平均时间复杂度为 O(n log n)。

优点:

  • 平均时间复杂度为 O(n log n),效率高。
  • 原地排序,空间复杂度为 O(log n)。

缺点:

  • 最坏情况下时间复杂度为 O(n²),但可以通过随机化基准元素来减少概率。
  • 不稳定排序。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • JavaScript Window localStorage使用
  • 基于springboot的智慧社区微信小程序
  • Linux中使用cp命令的 -f 选项,但还是提醒覆盖的问题
  • 【Web】御网杯信息安全大赛2024 wp(全)
  • Python语法(二)——函数
  • vue3 组合式API defineEmits() 与 emits 组件选项
  • STM32 单片机最小系统全解析
  • Linux自主学习篇
  • Qt Creator项目模板介绍
  • 视频相关处理
  • MQ入门(4)
  • 【Python】Maya:为人类打造的 Python 日期时间库
  • 抓机遇,促发展——2025第十二届广州国际汽车零部件加工技术及汽车模具展览会
  • Java内存泄漏排查
  • Ansible部署与应用基础
  • 【译】理解JavaScript:new 关键字
  • android图片蒙层
  • Meteor的表单提交:Form
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • SpriteKit 技巧之添加背景图片
  • 包装类对象
  • 闭包--闭包作用之保存(一)
  • 对超线程几个不同角度的解释
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 深入浅出Node.js
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 用 Swift 编写面向协议的视图
  • 正则学习笔记
  • nb
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #Linux(权限管理)
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (3)(3.5) 遥测无线电区域条例
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (PySpark)RDD实验实战——求商品销量排行
  • (Python) SOAP Web Service (HTTP POST)
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (七)Flink Watermark
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (学习日记)2024.01.19
  • ***通过什么方式***网吧
  • .locked1、locked勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET分布式缓存Memcached从入门到实战
  • .NET连接数据库方式
  • :O)修改linux硬件时间
  • @hook扩展分析
  • [ CTF ] WriteUp- 2022年第三届“网鼎杯”网络安全大赛(朱雀组)
  • []常用AT命令解释()
  • [000-01-022].第03节:RabbitMQ环境搭建
  • [AI 大模型] Meta LLaMA-2
  • [AI资讯·0612] AI测试高考物理题,最高准确率100%,OpenAI与苹果合作,将ChatGPT融入系统中,大模型在物理领域应用潜力显现
  • [android] 请求码和结果码的作用