【JS 排序算法】

排序算法

    • 冒泡排序
    • 选择排序
    • 插入排序
    • 希尔排序
    • 归并排序
    • 快速排序
    • 堆排序
    • 计数排序
    • 桶排序
    • 基数排序

冒泡排序

冒泡排序是一种简单的排序算法,它的基本思想是重复地比较相邻两个元素的大小,并交换它们,直到整个序列都有序为止。冒泡排序的时间复杂度为 O(n^2)。

下面是 JavaScript 中实现冒泡排序的代码:

function bubbleSort(arr) {let len = arr.length;for (let i = 0; i < len; i++) {for (let j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; // 交换相邻两个元素的值}}}return arr;
}

在这个代码中,我们使用了两个循环来遍历整个数组。外层循环控制比较轮数,内层循环控制每轮比较的次数。每次内层循环比较相邻两个元素的大小,并交换它们的位置,这样可以保证每轮循环之后,最大的元素都被移到了数组的最后面。最终,整个数组都会被排序好,我们将它返回即可。

使用示例:

let arr = [3, 1, 6, 2, 9, 4, 0, 5];
bubbleSort(arr); // [0, 1, 2, 3, 4, 5, 6, 9]

选择排序

选择排序(Selection Sort)是一种简单直观的排序算法,其基本思想是在待排序的元素中选出最小(或最大)的一个元素,与序列最左侧的元素交换位置,然后再从剩余未排序的元素中继续寻找最小(或最大)的元素,重复以上操作直到整个序列有序。

以下是选择排序的详细实现过程:

1.首先,我们找到数组中最小的元素。

2.其次,将最小元素和数组的第一个元素交换位置。

3.接着,在剩余的元素中找到最小元素,将其与数组的第二个元素交换位置。

4.重复以上步骤,一直到数组排序完成。

JavaScript实现代码如下:

function selectionSort(arr) {var len = arr.length;var minIndex, temp;for (var i = 0; i < len - 1; i++) {minIndex = i;for (var 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 = [64, 25, 12, 22, 11];
console.log(selectionSort(arr)); // [11,12,22,25,64]

选择排序是一种简单有效的排序算法,虽然它的时间复杂度为O(n^2),但是在小规模数据的排序中相对于其他高级排序算法具有一定的优势。

插入排序

插入排序是一种基本的排序算法,其基本思想是将待排序的元素插入到已经有序的数组中,以达到排序的目的。下面是 js 插入排序的详解。

  1. 算法步骤

插入排序的基本思路是,将待排序的元素插入到已经排好序的数组中,因此,插入排序的算法步骤如下:

  1. 将待排序的数组分为两个区间:已排序区间和待排序区间。

  2. 初始时,已排序区间只有一个元素,即数组的第一个元素。

  3. 将待排序区间的第一个元素插入到已排序区间的适当位置(如有必要,已排序区间需要将插入位置之后的元素后移)。

  4. 重复步骤 3,直到待排序区间中的所有元素都插入到已排序区间中。

  5. js 代码实现

以下是使用 js 实现插入排序的代码:

function insertionSort(arr) {for (let i = 1; i < arr.length; i++) {// 将当前元素插入到已排序区间的适当位置let j = i;while (j > 0 && arr[j] < arr[j - 1]) {[arr[j], arr[j - 1]] = [arr[j - 1], arr[j]];j--;}}return arr;
}// 示例:
let arr = [3, 1, 5, 7, 2, 4, 9, 6];
console.log(insertionSort(arr)); // 输出 [1, 2, 3, 4, 5, 6, 7, 9]
  1. 算法分析

插入排序算法的时间复杂度为 O(n^2)。虽然插入排序算法的时间复杂度不是最优的,但是它具有以下几个优点:

  1. 算法思路简单,易于理解和实现。
  2. 当待排序的元素数量比较少时(如少于 10 个),插入排序算法的效率比较高。
  3. 插入排序算法是稳定的,即排序前相同的元素,在排序后仍然保持相同的顺序。

希尔排序

希尔排序是一种改进的插入排序算法,也称缩小增量排序,它首先将数组分为若干子数组,然后对每个子数组进行插入排序,最后对整个数组进行一次插入排序。具体来说,希尔排序是通过将间隔 h 不断缩小进行插入排序的一种算法。

假设待排序的数组为 arr,希尔排序的实现过程如下:

  1. 确定初始步长 h,一般取数组长度的一半,然后将数组分为 h 个子数组。

  2. 分别对每个子数组进行插入排序,即将子数组中的元素按照从小到大的顺序进行排序。

  3. 将步长 h 缩小为原来的一半,重新分为 h/2 个子数组。

  4. 重复步骤 2 和 3,直到步长为 1,即整个数组变为一个子数组。

  5. 对整个数组进行一次插入排序,排序完成。

希尔排序的时间复杂度取决于步长序列的选择,一般情况下可以选择以下步长序列:

  1. Knuth 序列:h = 1, 4, 13, 40, …,其时间复杂度为 O(n^(3/2))。

  2. Hibbard 序列:h = 1, 3, 7, 15, …,其时间复杂度为 O(n^(3/2))。

  3. Sedgewick 序列:h = 1, 5, 19, 41, 109, …,其时间复杂度为 O(n^(4/3))。

希尔排序的优点是相较于冒泡排序、选择排序等简单排序算法更加高效,适用于大规模数据的排序。但是其实现过程比较复杂,需要对步长序列的选择进行优化,否则可能导致性能的下降。

归并排序

归并排序是一种基于分治思想的排序算法。它将问题分解成小问题,通过递归求解小问题,然后将小问题的解合并成大问题的解。具体实现过程如下:

  1. 将待排序数组分为两个子数组,分别对这两个子数组进行递归排序,直到子数组长度为 1 或 0。
  2. 合并两个已排好序的子数组。合并的过程中,将每个子数组的首元素进行比较,将较小的元素放入新的数组中,并将对应子数组的指针向后移动一位。当其中一个子数组的指针移动到末尾时,将另一个子数组的剩余元素直接拷贝到新的数组中。
  3. 返回合并后的数组作为结果。

JavaScript 代码实现:

function merge(left, right) {let 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++]);}}while (i < left.length) {result.push(left[i++]);}while (j < right.length) {result.push(right[j++]);}return result;
}function mergeSort(arr) {if (arr.length <= 1) {return arr;}let mid = Math.floor(arr.length / 2);let left = arr.slice(0, mid);let right = arr.slice(mid);left = mergeSort(left);right = mergeSort(right);return merge(left, right);
}

这里定义了两个函数,merge 函数用来合并两个已排好序的子数组,mergeSort 函数是递归函数,用来排序整个数组。函数的实现过程与上面提到的算法思想一致。

快速排序

快速排序是一种常见的排序算法,它采用了分治的思想,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再利用递归的方式将这两部分数据分别进行快速排序,最终达到整个序列有序的效果。在实现中,我们需要选取一个基准元素,一般选择第一个或最后一个元素作为基准,将序列中比基准元素小的放在左边,比基准元素大的放在右边,再递归地对左右两部分数据进行排序。

以下是 JavaScript 实现快速排序的代码:

function quickSort(arr) {if (arr.length <= 1) {return arr;}const pivotIndex = Math.floor(arr.length / 2);const pivot = arr.splice(pivotIndex, 1)[0];const left = [];const right = [];for (let i = 0; i < arr.length; i++) {if (arr[i] < pivot) {left.push(arr[i]);} else {right.push(arr[i]);}}return quickSort(left).concat([pivot], quickSort(right));
}

代码解释:

  1. 对于长度不超过 1 的数组,直接返回。
  2. 选择数组的中间元素作为基准元素 pivot。
  3. 将除了 pivot 以外的元素分为左右两个数组,左边的元素小于 pivot,右边的元素大于等于 pivot。
  4. 将左右两部分数据分别递归进行快速排序,并将左右数组和 pivot 拼接起来返回。

使用示例:

const arr = [6, 5, 3, 1, 8, 7, 2, 4];
const sortedArr = quickSort(arr);
console.log(sortedArr); // [1, 2, 3, 4, 5, 6, 7, 8]

堆排序

堆排序(Heap Sort)是一种树形选择排序算法,它是把无序数组构建成二叉堆,利用堆的特性进行排序的一种算法。堆的结构分为大根堆和小根堆。在堆中,最大的元素总是位于根节点。

堆排序的基本思想是:利用堆结构的特点(即大/小根堆)依次将堆顶元素与堆底元素交换位置并调整堆结构,这样,最后得到的就是一个有序序列了。

具体步骤如下:

  1. 构建堆:将无序数组构建成二叉堆,具体实现过程是从最后一个非叶子节点开始,依次将子树调整为堆,直到根节点。

  2. 堆排序:依次将堆顶元素与堆底元素交换位置,并调整堆结构,使得剩余元素仍然构成堆。重复执行该步骤,直到所有元素都有序。

JavaScript 实现代码如下:

function heapSort(arr) {function swap(arr, i, j) {[arr[i], arr[j]] = [arr[j], arr[i]];}function heapify(arr, n, i) {let largest = i;let l = 2 * i + 1;let r = 2 * i + 2;if (l < n && arr[l] > arr[largest]) {largest = l;}if (r < n && arr[r] > arr[largest]) {largest = r;}if (largest != i) {swap(arr, i, largest);heapify(arr, n, largest);}}function buildHeap(arr) {let n = arr.length;for (let i = Math.floor(n / 2) - 1; i >= 0; i--) {heapify(arr, n, i);}}buildHeap(arr);for (let i = arr.length - 1; i >= 0; i--) {swap(arr, 0, i);heapify(arr, i, 0);}return arr;
}// Example
let arr = [5, 3, 8, 4, 2];
let sortedArr = heapSort(arr);
console.log(sortedArr); // [2, 3, 4, 5, 8]

计数排序

计数排序是一种非比较排序算法,它适用于待排序序列中元素范围较小的情况。计数排序的主要思想是,统计待排序序列中每个元素出现的次数,然后根据元素出现的次数,输出排序后的序列。

具体的实现步骤如下:

  1. 找出待排序序列中最大值和最小值,确定元素的取值范围。

  2. 根据取值范围创建一个计数数组count,count[i]表示待排序序列中i出现的次数。

  3. 遍历待排序序列,统计每个元素出现的次数,记录在count数组中。

  4. 根据count数组中的计数信息,对待排序序列进行排序。

  5. 输出排序后的序列。

下面是JavaScript实现代码:

function countSort(arr) {// 找出待排序序列中最大值和最小值,确定元素的取值范围const maxValue = Math.max(...arr);const minValue = Math.min(...arr);const len = maxValue - minValue + 1;// 根据取值范围创建一个计数数组countconst count = new Array(len).fill(0);// 统计每个元素出现的次数,记录在count数组中for (let i = 0; i < arr.length; i++) {count[arr[i] - minValue]++;}// 根据统计信息,对待排序序列进行排序let sortedIndex = 0;for (let i = 0; i < len; i++) {while (count[i] > 0) {arr[sortedIndex++] = i + minValue;count[i]--;}}return arr;
}// 测试
const arr = [3, 1, 6, 2, 7, 2, 8, 4];
console.log(countSort(arr)); // [1, 2, 2, 3, 4, 6, 7, 8]

上述代码中,我们先找出待排序序列中的最大值和最小值,然后创建一个计数数组count,其中数组的长度为最大值和最小值之差加一。接着,我们遍历待排序数组,统计每个元素出现的次数,并记录在count数组中。最后,我们根据count数组中的统计信息,对待排序序列进行排序。排序完毕后,返回排序后的序列。

桶排序

桶排序是一种排序算法,它的基本思想是将待排序的元素分配到有限数量的桶中,然后对桶中元素进行排序,最后按照顺序将各个桶中元素依次排列得到排序结果。

以下是 JavaScript 实现桶排序的代码:

function bucketSort(arr, bucketSize) {if (arr.length === 0) {return arr;}let i;let minValue = arr[0];let maxValue = arr[0];for (i = 1; i < arr.length; i++) {if (arr[i] < minValue) {minValue = arr[i];} else if (arr[i] > maxValue) {maxValue = arr[i];}}// 桶数量let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;let buckets = new Array(bucketCount);for (i = 0; i < buckets.length; i++) {buckets[i] = [];}// 将元素分配到桶中for (i = 0; i < arr.length; i++) {buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);}// 对每个桶中的元素进行排序arr.length = 0;for (i = 0; i < buckets.length; i++) {insertionSort(buckets[i]);for (let j = 0; j < buckets[i].length; j++) {arr.push(buckets[i][j]);}}return arr;
}function insertionSort(arr) {let len = arr.length;let preIndex, current;for (let i = 1; i < len; i++) {preIndex = i - 1;current = arr[i];while (preIndex >= 0 && arr[preIndex] > current) {arr[preIndex + 1] = arr[preIndex];preIndex--;}arr[preIndex + 1] = current;}return arr;
}

该实现中使用了插入排序算法对每个桶中的元素进行排序。这是因为桶排序的时间复杂度取决于对每个桶中元素的排序算法,插入排序的时间复杂度为 O ( n 2 ) O(n^2) O(n2),但由于每个桶中的元素数量不超过 b u c k e t S i z e bucketSize bucketSize,所以插入排序是比较理想的选择。不过也可以使用其他的排序算法,比如快速排序或归并排序,以提高桶排序的效率。

基数排序

基数排序是一种非比较排序算法,适用于对整数进行排序。它的基本思想是将整数按位数切割成不同的数字,然后按每个位数分别进行排序。这个过程从低位到高位进行,也就是说,先排最低位,再排次低位,直到排完最高位。

以下是基数排序的 JavaScript 实现:

function radixSort(arr) {const maxNum = Math.max(...arr);let divisor = 1; // 除数,用于求每位的数字while (divisor <= maxNum) {const buckets = Array.from({ length: 10 }, () => []); // 10 个桶,用于存放每位数字相同的数字for (let i = 0; i < arr.length; i++) {const digit = Math.floor((arr[i] / divisor) % 10); // 求出当前数字的对应位数上的数字buckets[digit].push(arr[i]); // 将数字放入对应的桶中}arr = [].concat(...buckets); // 合并桶中的数字,组成新的 arr 数组divisor *= 10; // 将除数乘以 10,求下一位数字}return arr;
}

该实现中,我们先求出数组中的最大值,然后定义一个变量 divisor,初值为 1,每轮循环 divisor 都会乘以 10,这样可以依次求出数字的个位、十位、百位等等。在每轮循环中,我们创建 10 个桶,用于存放数字。我们将每个数字放入对应的桶中,最后将所有桶中的数字按顺序依次合并,组成新的数组。经过多轮的循环和桶的合并,我们就得到了有序的数组。

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

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

相关文章

利用 OLE 对象漏洞的 HWP 恶意文件浮出水面

ASEC 分析人员发现了一个利用 OLE 对象的恶意 HWP 文件&#xff0c;尽管其使用了 2020 年就被识别的恶意 URL&#xff0c;但仍然使用了 Flash 漏洞&#xff08;CVE-2018-15982&#xff09;&#xff0c;需要用户谨慎对待。 打开 HWP 文件时会在 %TEMP%文件夹中生成如下文件。攻…

【多音音频测试信号】具有指定采样率和样本数的多音信号,生成多音信号的相位降低波峰因数研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Java-day07(面向对象-3,4)

继承 将多个类中共有的属性&#xff0c;方法剥离出来单独创建一个共有类&#xff0c;当需要使用共有的属性与方法时&#xff0c;就可以通过继承(extends)来调用共有的属性与方法。通过"class A extends B" 来实现类的继承&#xff08;子类&#xff1a;A 父类&#x…

微前端初识

文章目录 微前端的发展历史微前端的定义微前端的特点使用微前端面临的挑战微前端常用技术方案及优缺点路由分发式微前端iframesingle-spaqiankunwebpack5: module federationWeb Component 微前端的发展历史 微前端在2016年首次出现在TWTR&#xff08;ThoughtWorks Technology…

gdb 调试汇编

starti 从第一条指令开始执行并停止. nexti 执行完当前指令; 当前指令可能是call一个函数, 但是仍然下一条指令才停止; stepi 下一条指令, 如果跳转也跟着跳转; 查看寄存器值 info registers 查看通用寄存器 info registers {register_name ...}指定寄存器的值 info reg…

MySQL之深入InnoDB存储引擎——Undo页

文章目录 一、UNDO日志格式1、INSERT操作对应的UNDO日志2、DELETE操作对应的undo日志3、UPDATE操作对应的undo日志1&#xff09;不更新主键2&#xff09;更新主键的操作 3、增删改操作对二级索引的影响 二、UNDO页三、UNDO页面链表四、undo日志具体写入过程五、回滚段1、回滚段…

java版直播商城平台规划及常见的营销模式 电商源码/小程序/三级分销+商城免费搭建 bbcbbc

​ Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务…

C# 12 预览版的新功能

作者&#xff1a;Kathleen Dollard 排版&#xff1a;Alan Wang Visual Studio 17.7 Preview 3 和 .NET 8 Preview 6 的发布推进了 C# 12的发展。此预览版包含的功能为将来的性能增强奠定了基础。现在&#xff0c;您能够在库中更方便的使用内联函数。此预览版首次推出了一项实验…

Mysql主从搭建 基于DOCKER

创建目录 #主节点目录 mkdir -p /home/data/master/mysql/#从节点目录 mkdir -p /home/data/slave/mysql/创建配置文件 # 主节点配置 touch /home/data/master/mysql/my.cnf# 从节点配置 touch /home/data/slave/mysql/my.cnf编辑配置文件 主节点配置文件 vim /home/data/m…

算法通关村第五关——n数之和问题解析

1. 两数之和问题 力扣第1题就是两数之和问题&#xff0c;给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那两个整数&#xff0c;并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一…

Ishikawa

Ishikawa 石川、鱼骨头、因果 其实我压根不知道 Ishikawa 这个日文就是石川&#xff0c;^_^&#xff0c;视乎也没啥影响

计算机网络基础

文章目录 网络协议初识协议分层OSI七层模型TCP/IP五层协议 网络传输基本流程网络传输流程数据包装和分用封装过程分用过程 网络中的地址管理IP地址MAC地址 网络协议初识 协议是一种约定。 协议分层 分层之后&#xff0c;每一层只关注自己同层的功能&#xff0c;只使用下层的接…

卷积神经网络实现MNIST手写数字识别 - P1

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;365天深度学习训练营-第P1周&#xff1a;实现mnist手写数字识别&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同…

【Hystrix技术指南】(1)基本使用和配置说明

这世间许多事物皆因相信而存在&#xff0c;所以人们亲手捏出了泥菩萨&#xff0c;却选择坚定的去信仰它。 分布式系统的规模和复杂度不断增加&#xff0c;随着而来的是对分布式系统可用性的要求越来越高。在各种高可用设计模式中&#xff0c;【熔断、隔离、降级、限流】是经常被…

一个好的人力资源管理系统包括哪些部分

阅读本文&#xff0c;您将具体详细了解&#xff1a;一个好的人力资源管理系统应该包括哪些部分。 人事部门是一家公司重要的职能部门之一&#xff0c;为公司的持续性、健康性发展提供人力保障。 然而&#xff0c;目前传统的人事管理方式在应对一些问题时存在着一些挑战。 例…

Shell脚本学习-循环的控制命令

break continue exit对比&#xff1a; 示例1&#xff1a;break命令跳出整个循环。 [rootabc scripts]# cat break1.sh #!/bin/bashfor((i0;i<5;i)) doif [ $i -eq 3 ]thenbreakfiecho $i done echo "ok"[rootabc scripts]# sh break1.sh 0 1 2 ok可以看到i等于3及…

jupyter lab环境配置

1.jupyterlab 使用虚拟环境 conda install ipykernelpython -m ipykernel install --user --name tf --display-name "tf" #例&#xff1a;环境名称tf2. jupyter lab kernel管理 show kernel list jupyter kernelspec listremove kernel jupyter kernelspec re…

AttributeError: ‘NoneType‘ object has no attribute ‘flush‘

问题描述 当你的项目中使用了transformers库&#xff0c;并且使用 pyinstaller 打包无控制台窗口的程序时就会报这个错。 Traceback (most recent call last): File "main.py", line 4, in <module> File "<frozen importlib._bootstrap>", …

微信小程序--原生

1&#xff1a;数据绑定 1&#xff1a;数据绑定的基本原则 2&#xff1a;在data中定义页面的数据 3&#xff1a;Mustache语法 4&#xff1a;Mustache的应用场景 1&#xff1a;常见的几种场景 2&#xff1a;动态绑定内容 3&#xff1a;动态绑定属性 4&#xff1a;三元运算 4&am…

C语言:打开调用堆栈

第一步&#xff1a;打断点 第二步&#xff1a;FnF5 第三步&#xff1a;按如图找到调用堆栈