有且仅有的10个常见的排序算法,东西不多,怎么就背不下来呢

就这么跟你说吧,面试中肯定会出排序算法的算法题,你只需要背下来代码+背下来他们的时间复杂度和空间复杂度就能蒙混过关。

不管你是前端还是后端,关于排序的算法有且仅有这 10个,如果你用心了,怎么会记不住呢。看完这篇文章你还没记住,就说明你是笨蛋。

好吧,最最坏的情况下,也需要记住这个8【冒泡、选择、插入、希尔、归并、快速、桶、堆】

可以把所有排序分成三类

第一类【冒泡 + 选择 + 插入 + 希尔】重点是使用【循环+交换】

第二类【归并 + 堆排序 + 快速】重点是【辅助函数 + 递归】

第三类【快速排序】他自己一组,说明很重要,使用【递归思想

第三类【计数 + 桶 + 基数】重点是使用【额外空间桶】

一、循环+交换

1.1 冒泡排序

这个是你必须会的,我记得之前最先学的就是这个算法,因为他最简单,但是因为他的时间复杂度大,所以考的概率确实最小的,但是你怎么可以不会这么简单的排序呢?

冒泡排序分为三个,一个是基本的冒泡排序,二个改进的冒泡排序,我建议是至少记住一个基本的一个改进的。冒泡排序的时间复杂度都是 o(n^2)

改进的冒泡排序你一定要学会,因为如果你在面试中答了简单的冒泡排序,面试官一定会问你,有没有什么地方可以优化?如果你一步到位写出改进的冒泡排序说不定人家就放过你了。

1.1.1 基本的冒泡排序

记住一个关键字【双层 for 循环】

  1. 外层 for 循环 i < len
  2. 内层 for 循环 j 初始化为 0,j < len - i - 1
  3. 使用内层 for 循环交换元素
  4. 时间复杂度是 n^2, 因为有两层 for 循环
  5. 注意是升序排序,还是降序排序
function bubbleSort(arr) {let len = arr.lengthfor (let i = 0; i < len; i++) {for (let j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {let temp = arr[j + 1]arr[j + 1] = arr[j]arr[j] = temp}}}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(bubbleSort(arr));

1.1.2 改进的冒泡排序

记住关键子【while 循环 + for 循环 + pos 位置信息】

  1. 设置一个位置信息 pos 记录每趟排序中最后一次进行交换的位置
  2. pos 初始化为0 ,在 while 循环内初始化,每次循环都重置
  3. pos 位置之后的记录均已经交换到位
  4. 在交换的时候 if 语句内更新 pos
  5. 内层 for 循环 j < i 
  6. 在下一趟排序时,只需要扫描到 pos 位置即可【说明 posm是用来改变循环终止位置的】
  7. 注意 while 循环一定要有更改 while 循环条件的语句,这里就使用 pos
  8.  时间复杂度还是为O(N^2)

function bubbleSort(arr) {let i = arr.length - 1while (i > 0) {let pos = 0for (let j = 0; j < i; j++) {if (arr[j] > arr[j + 1]) {// 记录位置pos = jlet temp = arr[j + 1]arr[j + 1] = arr[j]arr[j] = temp}}// 更改 while 循环条件i = pos}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(bubbleSort(arr));

1.1.3 终极版的冒泡排序

关键值【while 循环和2个for循环 +下标 最大值和最小值】

  1. 这个是在 1.2 的基础上再进行优化的
  2. 关键是使用最大值和最小值的概念【这里是指的下标的最大最小值】
  3. 正向冒泡,找到最大值
  4. 反向冒泡, 找到最小值
  5. 2个 for 循环,不是双层 for 循环
  6. while 循环条件是 low < high 所以内部有high-- low ++的语句
  7. 要定义四个变量
  8. 排序趟数几乎减少了一半
function bubbleSort(arr) {let low = 0;let high = arr.length - 1let temp, jwhile (low < high) {// 注意这个是 j + 1 和 j 的交换for (j = low; j < high; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j + 1]arr[j + 1] = arr[j]arr[j] = temp}}high--// 这个 for 循环是 j - 1 和 j的交换for (j = high; j > low; j--) {if (arr[j - 1] > arr[j]) {temp = arr[j - 1]arr[j - 1] = arr[j]arr[j] = temp}}low++}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(bubbleSort(arr));

1.2 选择排序

重点【双层 for 循环】

  1. 找到数据结构中的最小值,并把放在第一位。
  2. 选择排序的时间复杂度也是O(n^2)
  3. 也是使用 双层的for循环
  4. 外层 for 循环交换当前值和 最小值,外层循环小于 len - 1,因为内层循环初始化为i+1
  5. 内层 for 循环用来寻找最小值【j = i + 1】
  6. 使用 minIndex 存最小值的下标,初始化为 i
function selectSort(arr) {let len = arr.lengthlet temp, minIndexfor (let i = 0; i < len - 1; i++) {minIndex = ifor (let j = i + 1; j < len; j++) {if (arr[j] < arr[minIndex]) {minIndex = j}}temp = arr[i]arr[i] = arr[minIndex]arr[minIndex] = temp}return arr}
var arr = [1, 10, 8, 2, 30];
console.log(selectSort(arr));

1.3 插入排序

这个插入排序也一定要会

重点【外层 for + 内层 while 】

  1. 时间复杂度依旧为 O(n^2)
  2. 外层使用 for 循环,初始化 i = 1【这就意味着使用j-1】
  3. 内层使用 while 循环 j = i
  4. 关键是 while 循环的条件
    1. 比较放在 while 循环的条件中 arr[j-1] > arr[i]
    2. 使用的是 j - 1, j--
  5. 交换发生在 for 循环中
  6. 适用于排小数组
function insertSort(arr) {let len = arr.lengthlet tempfor (let i = 1; i < len; i++) {temp = arr[i]let j = iwhile (j > 0 && arr[j - 1] > temp) {arr[j] = arr[j - 1]j--}arr[j] = temp}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(insertSort(arr));

1.4 希尔排序

希尔排序可以说是特殊的插入排序

重点是有一个【间隔 + while 循环 + for 循环  + while 循环】

  1. gap 初始化为 len /2,更新 gap = gap /2
  2. while 循环条件是 gap > 0
  3. 在插入排序的基础上外面加了一个 gap 的while循环
  4. gap 是for 循环的初始值【普通插入排序是1】
  5. 插入排序的 j-1 变成 j -gap
  6. 大幅减少数据移动的次数
function shellSort(arr) {let len = arr.lengthlet gap = Math.floor(len / 2)while (gap > 0) {for (let i = gap; i < len; i++) {const temp = arr[i]let j = iwhile (j >= gap && arr[j - gap] > temp) {arr[j] = arr[j - gap]j -= gap}arr[j] = temp}gap = Math.floor(gap / 2)}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log('希尔排序', shellSort(arr));

二、辅助函数+递归

2.1 归并排序

重点【两个函数 + 递归】

  1. 时间复杂度是O(nlogn)
  2. 将整个数组分为两个数组
  3. 对两个数组分别使用递归,调用两次
  4. 写一个辅助函数
  5. 第二个函数类似合并两个有序数组【使用双指针】
  6. 最后调用辅助函数
function merge(left, right) {let res = []let i = 0, j = 0while (i < left.length && j < right.length) {if (left[i] < right[j]) {res.push(left[i])i++}else {res.push(right[j])j++}}if (i < left.length) {res = res.concat(left.slice(i))}if (j < right.length) {res = res.concat(right.slice(j))}return res
}
function mergeSort(arr) {let len = arr.lengthif (len < 2) {return arr}let middle = Math.floor(len / 2)let left = arr.slice(0, middle)let right = arr.slice(middle)return merge(mergeSort(left), mergeSort(right))
}
var arr = [1, 10, 8, 2, 30];
console.log(mergeSort(arr));

2.2 堆排序

重点是【3个函数+递归】

  1. 总共需要3个函数,其中两个辅助函数,一个构建最大堆,一个调整堆
  2. 每个函数都需要调用调整堆的函数 heapify
  3. heapify 递归调用自身
  4. 两个 for 循环都是递减的
  5. 堆的性质:在一个最大堆(或最小堆)中,堆顶元素总是数组中最大(或最小)的元素
  6. 时间复杂度是O(n log n)

function heapSort(arr) {// 构建最大堆buildMaxHeap(arr);// 从最后一个非叶子节点开始向上调整堆for (let i = arr.length - 1; i > 0; i--) {// 将堆顶元素(最大值)与当前未排序部分的最后一个元素交换[arr[0], arr[i]] = [arr[i], arr[0]];// 调整堆,使其满足最大堆性质heapify(arr, 0, i);}return arr;
}// 构建最大堆
function buildMaxHeap(arr) {const len = arr.length;// 从最后一个非叶子节点开始向上调整堆for (let i = Math.floor(len / 2) - 1; i >= 0; i--) {heapify(arr, i, len);}
}// 调整堆
function heapify(arr, i, len) {let largest = i; // 当前节点const left = 2 * i + 1; // 左子节点const right = 2 * i + 2; // 右子节点// 如果左子节点比当前节点大,则更新最大值索引if (left < len && arr[left] > arr[largest]) {largest = left;}// 如果右子节点比当前节点大,则更新最大值索引if (right < len && arr[right] > arr[largest]) {largest = right;}// 如果最大值索引不是当前节点,则交换节点,并递归调整堆if (largest !== i) {[arr[i], arr[largest]] = [arr[largest], arr[i]];heapify(arr, largest, len);}
}var arr = [1, 10, 8, 2, 30];
console.log('堆-排序', heapSort(arr));

三、快速排序

快速排序是一定一定会考的,频率最高的算法,就算被也要背下来,你看他的名字里面有快速两个字,就说明他的重要性。

通过一趟排序将待排序记录分割成独立的两部分,其中一步跟记录的关键字均比另一部分的关键字小,则可分别将两部分记录继续进行排序,达到整个序列有序。

关键字【分治法 + 递归】

  1. 时间复杂度为 O(nlogn)
  2. 有一个基准,每次递归只初始化一次基准,不会手动修改
  3. 有一个小于基准的数组
  4. 一个大于基准的数组
  5. 有一个 for 循环,有一个 continue 语句
  6. 在函数返回的地方,使用递归
function quickSort(arr) {if (arr.length <=1) {return arr}let baseIndex = Math.floor(arr.length / 2)let base = arr[baseIndex]let less = []let greater = []for(let i =0; i < arr.length; i ++) {if (i === baseIndex) {continue}if(arr[i] < base) {less.push(arr[i])} else {greater.push(arr[i])}}return [...quickSort(less), base, ...quickSort(greater)]
}
var arr = [1, 10, 8, 2, 30];
console.log(quickSort(arr));

四、额外桶空间

4.1 计数排序

分布式排序,使用一个用来存储每个元素在原始数组中出现次数的临时数组,在所有元素都计数完成后,临时数组已排好序,并可以带以构建排序后的结果数组

重点【找到最大值和最小值+一个计数数组】

  1. 时间复杂度是O(o+k),k是临时计数数组的大小
  2. 找出数组中的最大值最小值
  3. 计算每个元素的出现次数 arr[i] -min 
  4. 计数数组,重建排序后的数组
  5. 适用于整数数组的排序
function countSort(arr) {// 找出最大值和最小值let min = max = arr[0]for (let i = 1; i < arr.length; i++) {if (arr[i] < min) {min = arr[i]}if (arr[i] > max) {max = arr[i]}}// 由于是计数排序适用于整数数组,所以这样初始化数组const countArr = new Array(max - min + 1).fill(0)for (let i = 0; i < arr.length; i++) {countArr[arr[i] - min]++ // 用数组下标对应一个元素}// 结果数组的 indexlet sortedIndex = 0for (let i = 0; i < countArr.length; i++) {while (countArr[i] > 0) {// 因为计数数组中减去了 min// 所以这里面要使用循环的下标 i 加上 最小值 minarr[sortedIndex] = i + minsortedIndex++countArr[i]--}}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(countSort(arr));

4.2 桶排序

也是分布式排序,重点是【分桶+插入排序】

  1. 和计数排序一样,先找到最大值和最小值
    1. 最大最小值,用于计算桶的个数
    2. 最小值,还用于把元素加入桶
  2. 有两个函数
  3. 第一个个函数将元素分成不同的桶
    1. 有两个参数,第二个参数是桶的大小
  4. 将元素插入桶,重点是计算bucketIndex = (arr[i]-min )/ bucketSize
  5. 第二个函数对桶进行排序,使用插入排序,因为插入排序用来排小数组不错
  6. 时间复杂度 O(n+k)

function bucketSort(arr, bucketSize = 5) {if (arr.length ===0) {return arr}let min = arr[0]let max = arr[0]for(let i = 1; i < arr.length; i++) {if(arr[i] < min) {min = arr[i]}if (arr[i] > max) {max = arr[i]}}const bucketCount = Math.floor((max- min)/bucketSize ) + 1const bucketArr = Array.from({length: bucketCount}, () => [])for(let i =0; i < arr.length; i++) {let bucketIndex = Math.floor((arr[i] - min) / bucketSize)bucketArr[bucketIndex].push(arr[i])}let sortedArr = []for(let i = 0; i < bucketArr.length; i ++) {insertSort(bucketArr[i])sortedArr.push(...bucketArr[i])}return sortedArr
}
var arr = [1, 10, 8, 2, 30];
console.log(bucketSort(arr));

4.3 基数排序

重点是【获取最大数的位数+桶的个数时基数的大小】

  1. 需要获取数组中的最大值
  2. 桶的个数时基数的大小,通常是10进制就是10
  3. 使用一个辅助函数获取指定位置上的数字
  4. 时间复杂度是 O(n+k)
function radixSort(arr) {let maxNum = Math.max(...arr)let maxLen = `${maxNum}`.length// 通常创建桶的数量是基数的大小// Array.from 的第二个参数时map函数依次迭代let buckets = Array.from({ length: 10 }, () => [])// 获取数字num的指定位数上的数字const getDigit = (num, digit) => {// Math.pow返回基数得幂return Math.floor(Math.abs(num) / Math.pow(10, digit)) % 10}for (let i = 0; i < maxLen; i++) {for (let j = 0; j < arr.length; j++) {let digit = getDigit(arr[j], i)buckets[digit].push(arr[j])}arr = [].concat(...buckets)for (let j = 0; j < 10; j++) {buckets[j] = []}}return arr
}
var arr = [1, 10, 8, 2, 30];
console.log(radixSort(arr));

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

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

相关文章

docker安装并跑通QQ机器人实践(2)-签名服务器bs-qsign搭建

在前文中&#xff0c;我们详尽阐述了QQ机器人的搭建过程及其最终实现的各项功能展示。接下来&#xff0c;我们将转向探讨该项目基于Docker构建服务的具体实践。本篇将以QQ机器人签名服务——qsign为起点&#xff0c;逐步展开论述。 1 获取和运行 xzhouqd/qsign:8.9.63 镜像 1.…

社交媒体数据恢复:YY语音

YY语音数据恢复指南 在我们的日常生活中&#xff0c;数据丢失是一种常见的现象。有时候&#xff0c;我们可能会不小心删除了重要的文件&#xff0c;或者因为硬件故障而导致数据丢失。在这种情况下&#xff0c;数据恢复软件可以帮助我们找回丢失的数据。本文将重点介绍如何使用Y…

Element中DatePicker日期选择器跨度只能选一年如何实现?

只需要给标签加上pickerOptions&#xff0c;当前时间日期选择器特有的选项参考下表 <el-date-pickerv-model"FormData.time"value-format"yyyy:MM:DD":picker-options"pickeroptions"type-"daterange"range-separator"至"…

C# Winform DataGridView的列顺序,在运行时/数据源绑定后被改变的问题

如题&#xff1a; C# Winform DataGridView的列顺序&#xff0c;在运行时/数据源绑定后被改变的问题&#xff0c;这个问题对于需要控制列顺序的人来说&#xff0c;如果找不到原因&#xff0c;你就会发现一直都控制不了列的顺序。 当然&#xff0c;你可能也有事件处理程序或者…

Day91:API攻防-接口安全SOAPOpenAPIRESTful分类特征导入项目联动检测

目录 API分类特征-SOAP&OpenAPI&RESTful API分类特征 API常见漏洞 API检测流程 API检测项目-Postman&APIKit&XRAY 工具自动化-SOAP - WSDL Postman 联动burpxray APIKit插件(可联动xray) 工具自动化-OpenApi - Swagger Postman 联动burpxray APIKit…

【可实战】测试体系与测试方案设计(业务按公司实际情况,技术可参考通用测试方案)

一、如果我们要测试一个系统&#xff0c;首先我们要了解被测系统的架构 &#xff08;一&#xff09;业务架构-从需求里面去了解&#xff08;角色和行为&#xff09;&#xff1a; 业务模型分析&#xff08;是一个电商&#xff0c;还是一个企业的crm&#xff0c;还是一个网站&a…

科技驱动未来,提升AI算力,GPU扩展正当时

要说这两年最火的科技是什么&#xff1f;我想“AI人工智能”肯定是最有资格上榜的&#xff0c;尤其ChatGPT推出后迅速在社交媒体上走红&#xff0c;短短5天&#xff0c;注册用户数就超过100万&#xff0c;2023年一月末&#xff0c;ChatGPT的月活用户更是突破1亿&#xff0c;成为…

Visual Components:3D工厂仿真软件 | 离散物流、机器人编程与PLC调试

在数字化浪潮席卷全球制造业的今天&#xff0c;一款强大的3D工厂仿真软件已经成为企业提升生产效率、优化流程设计的关键工具。而Visual Components&#xff0c;正是这场变革中的领军者。本文将带您深入探索这款软件的核心功能与优势&#xff0c;揭示其如何在离散物流、机器人编…

python re.split()函数解析

re.split简单的使用方法&#xff1a; resultre.split(表达式,字符串,re.S)根据表达式拆分字符串并返回数组 如果拆分文本&#xff0c;比如拆分一本小说内容如下 ss第一章 第一章标题\n fadfasdfasdfadafd\n 第二章 第二章标题\n adfafdasdfasdfadsfasd\n 第三章 第三章…

每天学习一个Linux命令之chmod

每天学习一个Linux命令之chmod 在Linux系统下&#xff0c;chmod命令用于改变文件或目录的权限。通过分配不同的权限&#xff0c;我们可以控制用户对文件或目录的访问、读取、写入和执行的权限。本篇博客将详细介绍chmod命令的使用方法和常用选项。 命令语法 chmod命令的一般…

uniapp --- 实现图片压缩(兼容H5)

目录 创建组件 在 template 中添加组件 方法说明&#xff1a; compress() 方法参数&#xff1a; progress 方法回调对象属性详细说明&#xff1a; 源码示例&#xff1a; thank Canvas 是 HTML5 提供的一个用于在网页上绘制图形的元素&#xff0c;它可以实现图片压缩的功…

介绍与部署 Zabbix 监控系统

目录 前言 一、监控系统 1、主流的监控系统 2、监控系统功能 二、Zabbix 监控系统概述 1、Zabbix 概念 2、Zabbix 主要特点 3、Zabbix 主要功能 4、Zabbix 监控对象 5、Zabbix 主要程序 6、Zabbix 监控模式 7、Zabbix 运行机制 8、Zabbix 监控原理 9、Zabbix 主…

mybatis批量查询List实体类

在 MyBatis 中进行批量查询 List 实体类的操作通常使用 foreach 标签来实现。下面是一个示例代码&#xff0c;展示了如何在 MyBatis 中批量查询 List 实体类&#xff1a; 根据主键id 假设有一个名为 User 的实体类&#xff1a; public class User {private Long id;private …

Python3中的模块

模块&#xff1a;创建的py文件 包&#xff1a;创建文件夹&#xff0c;文件夹中放很多的py文件 在一个py文件里调用另外一个py文件里的函数&#xff0c;例子 # 这个文件是主文件&#xff0c;app.py 文件# 调用其他自定义的模块 # 导入非嵌套层级的模块 import exampledef run(…

Git回滚操作,工作区和暂存区恢复修改删除的文件

在利用git协作过程中&#xff0c;经常需要进行代码的撤销操作&#xff0c;这个行为可能发生在工作区&#xff0c;暂存区或者仓库区&#xff08;或版本库&#xff09;。 我们先讨论在工作区与暂存区发生的撤销行为&#xff0c;这里会有两个命令提供帮助&#xff0c;git restore…

Day 15 Linux网络管理

IP解析 IP地址组成&#xff1a;IP地址由4部分数字组成&#xff0c;每部分数字对应于8位二进制数字&#xff0c;各部分之间用小数点分开&#xff0c;这是点分2进制。如果换算为10进制我们称为点分10进制。 每个ip地址由两部分组成网络地址(NetID)和主机地址(HostID).网络地址表…

Spring-Aop源码解析(中)

Spring-Aop源码解析&#xff08;上&#xff09;上文讲解了到底什么是Aop&#xff0c;以及围绕方法该如何去找对应的增强点&#xff0c;包括整个Advisor链路的执行顺序&#xff0c;本文来对上文中存在的一些关键点进行一个深入挖掘 Advice:要增强的逻辑&#xff0c;就是我们执行…

养猫必看!毛发护理秘籍,猫粮选择大揭秘!

亲爱的猫友们&#xff0c;我们都知道&#xff0c;猫咪的毛发是它们健康与美丽的象征。选择一款合适的猫粮&#xff0c;对于猫咪的毛发健康至关重要。那么&#xff0c;如何根据猫咪的毛发情况来选择合适的猫粮呢&#xff1f;接下来&#xff0c;就让我来为你详细解答吧&#xff0…

PDF文档电子签名怎么做?

如何确保电子文档的签署具有公信力和法律效力&#xff0c;防止伪造和假冒签名等问题&#xff0c;是电子文档无纸化应用面临的重要挑战。本文将详细介绍PDF文档电子签名的概念、重要性、实施步骤以及相关的法律背景&#xff0c;帮助用户理解并有效应用PDF文档电子签名技术。 1.…

Unity HDRP 2021 Release-Notes

&#x1f308;Unity HDRP 2021 Release-Notes 本文信息收集来自自动搜集工具&#x1f448; 版本更新内容2021.3.33HDRP: Added additional documentation for cached shadows of directional lights.2021.3.33HDRP: Added in which space custom velocity should be computed.…