各种排序方法总结

目录

1. 冒泡排序 (Bubble Sort

2. 选择排序 (Selection Sort)

3. 插入排序 (Insertion Sort)

4. 快速排序 (Quick Sort)

5. 归并排序 (Merge Sort)

6. 堆排序 (Heap Sort)


排序算法 时间复杂度 空间复杂度 备注
冒泡排序 最好情况: O(n)
平均情况: O(n^2)
最坏情况: O(n^2)
 O(1)  原地排序,只需常量级额外空间
选择排序

最好情况: O(n^2)

平均情况: O(n^2)
最坏情况: O(n^2)

 O(1) 原地排序,只需常量级额外空间
插入排序最好情况: O(n)
平均情况: O(n^2)
最坏情况: O(n^2)
 O(1) 原地排序,只需常量级额外空间
快速排序最好情况: O(n log n)
平均情况: O(n log n)
最坏情况: O(n^2
O(log n) 递归调用栈空间,最好情况O(log n),最坏情况O(n),但平均情况为O(log n)
归并排序最好情况:O(n log n)
平均情况: O(n log n)
最坏情况: O(n log n)
 O(n)  需要额外的临时数组来存储合并结果
堆排序最好情况: O(n log n)
平均情况: O(n log n)
最坏情况: O(n log n)
O(1)  原地排序,堆的调整过程在数组内部进行,只需常量级额外空间(不考虑递归实现,若考虑递归则与快速排序类似)

1. 冒泡排序 (Bubble Sort

时间复杂度:

  • 最好情况: O(n)
  • 平均情况: O(n^2)
  • 最坏情况: O(n^2)
function bubbleSort(arr) {  let n = arr.length;  for (let i = 0; i < n - 1; i++) {  for (let j = 0; j < n - 1 - i; j++) {  if (arr[j] > arr[j + 1]) {  // 交换元素  [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];  }  }  }  return arr;  
}

2. 选择排序 (Selection Sort)

原理:

选择排序是一种简单直观的排序算法。它的工作原理是首先在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

具体步骤如下:

  1. 从未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中继续寻找最小(或最大)元素,放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

特点:

  • 选择排序的时间复杂度为O(n^2),其中n是待排序元素的数量。
  • 选择排序是一种原地排序算法,因为它只需要一个额外的空间来存储当前找到的最小(或最大)元素。
  • 选择排序不是稳定的排序算法,因为相同元素的相对位置可能会在排序过程中发生改变。

时间复杂度:

  • 最好情况: O(n^2)
  • 平均情况: O(n^2)
  • 最坏情况: O(n^2)
function selectionSort(arr) {  let n = arr.length;  for (let i = 0; i < n - 1; i++) {  let minIndex = i;  for (let j = i + 1; j < n; j++) {  if (arr[j] < arr[minIndex]) {  minIndex = j;  }  }  // 交换元素  [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];  }  return arr;  
}

3. 插入排序 (Insertion Sort)

原理:

插入排序的工作方式是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,找到相应位置并插入时,不需要移动元素,只需将要插入的元素移动到插入点即可。

具体步骤如下:

  1. 从第一个元素开始,该元素可以认为已经被排序。
  2. 取出下一个元素,在已经排序的元素序列中从后向前扫描。
  3. 如果该元素(已排序)大于新元素,则将该元素移到下一位置。
  4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。
  5. 将新元素插入到该位置后。
  6. 重复步骤2~5,直到所有元素均排序完毕。

特点:

  • 插入排序的时间复杂度为O(n^2),在数据规模较小时表现良好,特别是当数据基本有序时,时间复杂度可以接近O(n)。
  • 插入排序是一种原地排序算法,因为它只需要一个额外的空间来存储当前正在插入的元素。
  • 插入排序是稳定的排序算法,因为相同元素的相对位置在排序过程中不会发生改变。

时间复杂度:

  • 最好情况: O(n)
  • 平均情况: O(n^2)
  • 最坏情况: O(n^2)
function insertionSort(arr) {  let n = arr.length;  for (let i = 1; i < n; i++) {  let key = arr[i];  let j = i - 1;  while (j >= 0 && arr[j] > key) {  arr[j + 1] = arr[j];  j = j - 1;  }  arr[j + 1] = key;  }  return arr;  
}

4. 快速排序 (Quick Sort)

原理:

快速排序是一种通过基准划分区块,再不断交换左右项的排序方式。它采用了分治法,减少了交换的次数。快速排序的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归或迭代进行,以此让整个数列变成有序序列。

具体步骤如下:

  1. 在待排序区间找到一个基准点(pivot),一般选择数组的第一个元素、最后一个元素或者随机选择一个元素。
  2. 逐个循环数组,将小于基准的项放在左侧,将大于基准的项放在右侧。一般通过交换的方式来实现。
  3. 对基准点左侧全部项和基点右侧全部项分别通过递归(或迭代)方式重复上述步骤,直到所有数组都交换完成。

时间复杂度:

  • 最好情况: O(n log n)
  • 平均情况: O(n log n)
  • 最坏情况: O(n^2) (但可以通过随机化选择基准元素等方法优化)
function quickSort(arr) {  if (arr.length <= 1) {  return arr;  }  let pivot = arr[Math.floor(arr.length / 2)];  let left = [];  let right = [];  for (let i = 0; i < arr.length; i++) {  if (i === Math.floor(arr.length / 2)) continue;  if (arr[i] < pivot) {  left.push(arr[i]);  } else {  right.push(arr[i]);  }  }  return [...quickSort(left), pivot, ...quickSort(right)];  
}

5. 归并排序 (Merge Sort)

原理:

归并排序是一种分治算法,其工作原理是将未排序的列表划分为n个子列表,每个子列表包含一个元素(包含一个元素的列表被认为是有序的),然后重复合并子列表以生成新的有序子列表,直到只剩下一个子列表。
具体步骤如下:

  1. 分解:将待排序的n个元素的序列分成两个子序列,每个子序列包含n/2个元素。
  2. 解决:使用归并排序递归地排序两个子序列。
  3. 合并:将两个已排序的子序列合并成一个最终的排序序列。

时间复杂度:

  • 最好情况: O(n log n)
  • 平均情况: O(n log n)
  • 最坏情况: O(n log n)
function mergeSort(arr) {  if (arr.length <= 1) {  return arr;  }  const middle = Math.floor(arr.length / 2);  const left = arr.slice(0, middle);  const right = arr.slice(middle);  return merge(mergeSort(left), mergeSort(right));  
}  function merge(left, right) {  let result = [];  let leftIndex = 0;  let rightIndex = 0;  while (leftIndex < left.length && rightIndex < right.length) {  if (left[leftIndex] < right[rightIndex]) {  result.push(left[leftIndex]);  leftIndex++;  } else {  result.push(right[rightIndex]);  rightIndex++;  }  }  return result.concat(left.slice(leftIndex)).concat(right.slice(rightIndex));  
}

6. 堆排序 (Heap Sort)

堆排序(Heap Sort)是一种基于堆(Heap)这种数据结构的比较排序算法。堆是一个近似完全二叉树的结构,分为最大堆(Max Heap)和最小堆(Min Heap)。在最大堆中,每个节点的值都大于或等于其子节点的值;在最小堆中,每个节点的值都小于或等于其子节点的值。堆排序通常使用最大堆来实现升序排序

堆排序原理:

  1. 构建最大堆:
  • 将数组看作一个完全二叉树,构建最大堆。
  • 从最后一个非叶子节点开始,向上依次调整堆,使得每个子树都满足最大堆的性质。

     2.堆排序过程:

  • 将堆顶元素(最大值)与堆的最后一个元素交换。
  • 堆的大小减1,重新调整堆顶元素所在的子树,使其满足最大堆的性质。
  • 重复上述步骤,直到堆的大小为1。

时间复杂度:

  • 最好情况: O(n log n)
  • 平均情况: O(n log n)
  • 最坏情况: O(n log n)
function heapSort(arr) {  let n = arr.length;  // 构建最大堆  for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {  heapify(arr, n, i);  }  // 一个个从堆顶取出元素  for (let i = n - 1; i > 0; i--) {  // 交换当前堆顶(最大值)和最后一个元素  [arr[0], arr[i]] = [arr[i], arr[0]];  // 重新调整堆  heapify(arr, i, 0);  }  return arr;  
}  function heapify(arr, n, i) {  let largest = i;  //最大子节点let left = 2 * i + 1;  //左子节点let right = 2 * i + 2;  //右子节点//如果左子节点存在且大于当前最大子节点if (left < n && arr[left] > arr[largest]) {  largest = left;  }  //如果右子节点存在且大于当前最大子节点if (right < n && arr[right] > arr[largest]) {  largest = right;  }  //如果最大值不是当前子节点,则交换 if (largest !== i) {  [arr[i], arr[largest]] = [arr[largest], arr[i]];  heapify(arr, n, largest);  }  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/56425.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

制冷压缩机液击介绍

液态制冷剂或润滑油随气体吸入压缩机气缸时损坏吸气阀片的现象,以及进入气缸后没有在排气过程迅速排出,在活塞接近上止点时,被压缩而产生的瞬间高液压的现象通常被称为液击。液击可以在很短时间内造成压缩受力件 ( 如阀片、活塞、连杆、曲轴、活塞销等 )的损坏,是往复式压…

Linux:linux系统中目录的遍历

Linux系统中目录的遍历 1、Linux中目录的遍历(1)函数opendir(2)函数readdir(3)函数closedir(4)遍历指定目录的所有文件和子目录 1、Linux中目录的遍历 (1)函数opendir 打开需要被遍历的目录 DIR *opendir(const char *pathname);pathname&#xff1a;待遍历的目录return&#…

国际期货收费行情源CTP推送式/期货配资软件开发对接行情源的技术性说明

在现代金融市场中&#xff0c;期货交易因其高风险和高回报特性而备受关注。为了满足期货交易者的需求&#xff0c;开发高效、稳定和安全的期货交易软件变得尤为重要。本文将对国际期货收费行情源CTP推送式及期货配资软件的开发对接行情源的技术细节进行详细说明。 一、CTP&…

Sequelize 提示报错ERR_HTTP_HEADERS_SENT

ERR_HTTP_HEADERS_SENT 是一个在 Node.js 环境中常见的错误,它通常发生在尝试向一个已经发送了 HTTP 头部的响应对象发送更多头部或数据时。在 Sequelize(一个基于 promise 的 Node.js ORM,用于 Postgres, MySQL, MariaDB, SQLite 和 Microsoft SQL Server 数据库)的上下文…

AJAX——express框架

本文分享到此结束&#xff0c;欢迎大家评论区相互讨论学习&#xff0c;接下来我们将用一个案例来接着学习AJAX的内容&#xff0c;下一篇给大家准备一个案例的准备工作分享。

Android studio中排除文件功能的小总结

刚开始发现android studio的sourceSets的main下面java的excludes无效&#xff0c;改了好多次都没成功&#xff0c;以为关键字不支持&#xff0c;或者是gradle版本问题&#xff0c;结果查了半天没成功。后来经过对比发现是相对路径问题。 在此总结一下&#xff0c;希望节省大家…

本地连接linux服务器上的sqlite数据库

要从本地机器连接到 Linux 服务器上的 SQLite 数据库文件&#xff0c;你需要采取以下步骤&#xff1a; 确保你有权限访问 Linux 服务器。 使用 SSH 隧道将本地端口转发到远程服务器。这允许你通过加密连接安全地访问远程数据库。 在本地机器上使用 SQLite 客户端或编程语言来…

过拟合和欠拟合小解

过拟合&#xff08;Overfitting&#xff09;和欠拟合&#xff08;Underfitting&#xff09;是机器学习领域中常见的两种问题&#xff0c;它们分别代表模型在训练数据和测试数据上表现不佳的两种极端情况。 过拟合&#xff08;Overfitting&#xff09; 过拟合是指模型在训练数…

微知-如何临时设置服务器风扇转速?(ipmitool raw 0x30 0x30 0x02 0xff 0x40)

服务器风扇可以通过PWM输出来控制转速。 设置方式 设置单次PWM ipmitool raw 0x30 0x30 0x02 0xff 0x40如果要持续设置需要类似while循环持续输出&#xff1a; while true; do ipmitool raw 0x30 0x30 0x02 0xff 0x64; done > /dev/null参数说明&#xff1a; 其他参数&a…

ClaimsettlementController

目录 1、 ClaimsettlementController 1.1、 保存三包表 1.2、 审核预约单 1.3、 反审核预约单 ClaimsettlementController using QXQPS.Models; using QXQPS.Vo; using System; using System.Collections; using System.Collections.Generic; using System.Linq…

云原生后端开发指南:拥抱未来的可扩展架构

云原生后端开发指南&#xff1a;拥抱未来的可扩展架构 随着企业数字化转型的深入&#xff0c;传统的IT架构正在向云原生架构迁移。云原生是一种充分利用云计算交付模式的方法&#xff0c;结合微服务、容器化和DevOps&#xff0c;帮助企业构建灵活、可扩展和高效的系统。在这篇…

【java】数组(超详细总结)

目录 一.一维数组的定义 1.创建数组 2.初始化数组 二.数组的使用 1.访问数组 2.遍历数组 3.修改数据内容 三.有关数组方法的使用 1.toString 2. copyOf 四.查找数组中的元素 1.顺序查找 2.二分查找binarySearch 五.数组排序 1.冒泡排序 2.排序方法sort 六.数组逆置…

科研绘图系列:R语言突出强调部分的饼图(pie plot)

文章目录 介绍加载R包数据数据预处理画饼图画图例合并图形系统信息介绍 饼图(Pie Chart),也称为圆图(Circle Graph),是一种圆形的统计图表,通过将圆分成若干扇形来展示数据的比例关系。每个扇形的角度大小代表了相应数据在总量中的占比。饼图的特点包括: 比例展示:直…

Redis知识应用索引指南

Redis&#xff0c;全称为Remote Dictionary Server&#xff0c;是一个开源的高性能键值对数据库。它以其卓越的性能、丰富的数据结构和灵活的持久化机制&#xff0c;在现代应用中扮演着至关重要的角色 1 什么是redis Redis是一个使用ANSI C语言编写的开源、跨平台的键值存储系…

10用户管理(Vue3+Spring Boot)

目录 1. 功能描述2. 接口地址3.后台Java代码4.前端框架搭建&#xff1a;views/user添加UserManageVue组件5. api/user.js中写请求接口代码6 获取用户信息7 删除用户8 修改状态9 效果演示 1. 功能描述 用户管理界面&#xff0c;对用户进行查询、状态变更、删除。2. 接口地址 #…

Linux系统——lvm逻辑卷

Linux系统——lvm逻辑卷 一、lvm逻辑卷1、lvm操作流程2、操作指令 二、逻辑卷操作1、创建逻辑卷1.1 /dev/cloud/openstack 5G xfs /cloud/openstack1.2 /dev/cloud/docker 10G ext4 /cloud/docker 2、逻辑卷扩容2.1 扩容流程2.2 需求一&#xff1a;扩容ext4文件系统的逻辑卷2.3…

Ubuntu-Ubuntu22.04下Anacodna3的qmake和Qt的qmake冲突问题

Ubuntu22.04下Anacodna3的qmake和Qt的qmake冲突问题 一、问题描述二、原因分析三、解决办法 一、问题描述 Ubuntu22.04下Anacodna3的qmake和Qt的qmake冲突问题 zhyzhy-HP:~/Sources/mpv-examples/libmpv/qt$ make g -c -pipe -g -Wall -Wextra -D_REENTRANT -fPIC -DQT_WIDGET…

TypeScript中 interface接口 type关键字 enum枚举类型

type interface总是傻傻分不清~~~ Type Aliases (type) type 关键字用于为类型定义一个别名。这可以是基本类型、联合类型、元组、数组、函数等。type 定义的类型在编译后的 JavaScript 代码中会被移除&#xff0c;不会留下任何运行时的代码。 //联合类型 type StringOrNumbe…

SQL JOIN的学习

SQL JOIN (w3school.com.cn) 之前跟着老师学数据库的时候学过&#xff0c;最近又比较频繁的在使用。 再复习一下。 Id_P是主键 Id_O是主键 1. SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons, Orders WHERE Persons.Id_P Orders.Id_P 2. SEL…

Idea 2023.2.7构建SpringCloud多模块项目

Idea 2023.2.7构建SpringCloud多模块项目 本文介绍如何使用idea 2023.2.7构建基于SpringCloud alibaba微服务项目&#xff0c;基于Nacos注册中心。 环境准备&#xff1a; JDK版本&#xff1a;jdk17 SpringBoot:3.3.4 SpringCloud:2023.0.3 Nacos服务端:2.4.3 1、创建父工程&a…