JavaScript实现十大排序算法

news2024/11/19 12:37:00

目录

概览

一、冒泡排序

1、算法描述

2、图示

3、代码 

二、选择排序

1、算法描述

2、图示

 3、代码

三、插入排序

1、算法描述

2、图示

​编辑 3、代码

四、希尔排序

1、算法描述

2、图示

3、代码

五、并归排序

1、算法描述

2、图示

​编辑​编辑3、代码

六、快速排序

1、算法描述

2、图示

​编辑​编辑 3、代码

七、堆排序

1、算法描述

2、图示

3、代码

八、计数排序

1、算法描述

2、图示

3、代码

九、桶排序

1、算法描述

2、图示

3、代码

十、基数排序

1、算法描述

2、图示

3、代码


概览

十大排序算法可以分成两类:

  • 比较类别排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

在这里插入图片描述

算法的时间复杂度:

在这里插入图片描述 

相关概念:
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
 

!!以下算法均按照升序排序!!

一、冒泡排序

1、算法描述

从头开始,一次比较相邻的两个元素,如果前一个元素比后一个元素小,则往后移动一个元素继续比较;如果前一个元素比后一个元素大,则两个元素交换位置,再往后移一个元素继续比较。

每一趟比较下来,最后一个元素肯定是当前趟最大的,进行下一趟比较时,该元素就不再参与比较了。

2、图示

在这里插入图片描述

3、代码 

function bubbleSort(arr) {
  let len = arr.length;
  // 一共比较多少趟
  for (let i = 0; i < len - 1; i++) {
    // 每趟进行比较,j=要进行排序的元素个数,每一趟排下来最后1个元素都不进行下一趟的排序
    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;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(bubbleSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

二、选择排序

1、算法描述

每趟比较中找到最小的元素,将最小的元素与首元素进行位置交换,首元素就不再进行下一趟排序,重复操作直到完成排序

2、图示

在这里插入图片描述

 3、代码

function selectSort(arr) {
  let 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;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(selectSort(arr));  // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

三、插入排序

1、算法描述

  1. 第一个元素默认已排好序,从第二个元素开始。
  2. 如果第二个元素比第一个元素小,那就交换二者位置,否则不交换,前两个元素的顺序已经固定。
  3. 第三个元素与前两个元素进行比较,从后向前比,先与第二个元素比,如果比第二个元素小,再与第一个元素比,比第一个元素小,就放在第一个元素的位置,第一个元素和第二个元素向后移一个位置;如果第三个元素不比第二个元素小,不交换位置,这趟的排序以固定,也就是前三个元素的大小顺序已经排好。
  4. 之后的排序也是这么进行。

2、图示

在这里插入图片描述 3、代码

function insertSort(arr) {
  let len = arr.length;
  for (let i = 1; i < len; i++) {
    let now = arr[i]; // 当前趟的元素
    let lastIndex = i - 1; // 已经排好序的序列里的最后一个元素
    // 从后向前遍历已经排好序的序列
    // 如果当前趟的元素now比已经排好序的序列的元素小
    while (lastIndex >= 0 && arr[lastIndex] > now) {
      arr[lastIndex + 1] = arr[lastIndex]; // 将比now大的元素向后移一个位置
      lastIndex--;
    }
    arr[lastIndex + 1] = now; // 将当前趟的元素now插入到已经排好序的序列里
  }
  return arr;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(insertSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

四、希尔排序

插入排序的改进版。与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。

1、算法描述

  1. 选择一个增量 k=arr.length/2 进行排序,增量k为几就将该arr分成几组,每组有 arr.length/k=2 个元素。然后组内元素从前往后进行比较,按照升序排列好,再将小组并成一个大arr。
  2. 再次分组,分成k/2组,每个组有 arr.length/k/2 个元素,再次将组内元素按升序进行排序,排序好在并成大arr。
  3. 重复上述操作,直至arr排好序。
  4. 插入排序时,并不是一个分组内的数字一次性用插入排序完成,而是每个分组交叉进行。

2、图示

3、代码

function shellSort(arr) {
  let len = arr.length;
  // 第一次分组是k=arr.length/2,之后的每次分组都是k/2
  for (let k = Math.floor(len / 2); k > 0; k = Math.floor(k / 2)) {
    // 遍历每个分组的元素,i在分组里表示的是每个组内最后一个元素
    // 在原数组arr里表示的是分组后的第一个元素,然后后面的元素依次与前面的元素进行比较
    for (let i = k; i < len; i++) { // i控制当前进行排序的是哪一个小组
      let j = i;  // j控制的是当前小组的最后一个元素
      // 各小组内进行比较时,按升序排列
      while (j - k >= 0 && arr[j] < arr[j - k]) {
        [arr[j], arr[j - k]] = [arr[j - k], arr[j]];
        j = j - k;  // 让j变成当前小组的上一个元素
      }
    }
  }
  return arr;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(shellSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

五、并归排序

分治法

1、算法描述

把长度为n的arr分成两个长度为n/2的子序列,一直划分到最小个数之后,两两比较,合并成长度为2的小序列,然后再小序列间比较,一直重复合并成最终的arr

2、图示

3、代码

function mergeSort(arr) {
  let len = arr.length;
  if (len < 2) {
    return arr;
  }
  let mid = Math.floor(len / 2);
  let left = arr.slice(0, mid);
  let right = arr.slice(mid);
  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  let result = [];

  while (left.length > 0 && right.length > 0) {
    if (left[0] <= right[0]) {
      result.push(left.shift());
    } else {
      result.push(right.shift());
    }
  }

  while (left.length) {
    result.push(left.shift());
  }

  while (right.length) {
    result.push(right.shift());
  }
  return result;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(mergeSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

六、快速排序

分治法

1、算法描述

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

2、图示

在这里插入图片描述 3、代码

 

function quickSort(arr, left, right) {
  let len = arr.length,
    partitionIndex,
    left = typeofleft != "number" ? 0 : left,
    right = typeofright != "number" ? len - 1 : right;

  if (left < right) {
    partitionIndex = partition(arr, left, right);
    quickSort(arr, left, partitionIndex - 1);
    quickSort(arr, partitionIndex + 1, right);
  }
  return arr;
}

function partition(arr, left, right) {
  // 分区操作
  let pivot = left, // 设定基准值(pivot)
    index = pivot + 1;
  for (let i = index; i <= right; i++) {
    if (arr[i] < arr[pivot]) {
      swap(arr, i, index);
      index++;
    }
  }
  swap(arr, pivot, index - 1);
  return index - 1;
}

function swap(arr, i, j) {
  let temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(quickSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

七、堆排序

1、算法描述

  1. 通过构建大顶堆
  2. 将堆顶的最大数拿出,与堆底的叶子节点进行交换
  3. 接着,树剪掉最大数的叶子
  4. 再对堆进行调整,重新变成大顶堆
  5. 返回步骤2,以此循环,直至取出所有数

2、图示

在这里插入图片描述 

3、代码

var len; // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量

function buildMaxHeap(arr) {
  // 建立大顶堆
  len = arr.length;
  for (var i = Math.floor(len / 2); i >= 0; i--) {
    heapify(arr, i);
  }
}

function heapify(arr, i) {
  // 堆调整
  var left = 2 * i + 1,
    right = 2 * i + 2,
    largest = i;

  if (left < len && arr[left] > arr[largest]) {
    largest = left;
  }

  if (right < len && arr[right] > arr[largest]) {
    largest = right;
  }

  if (largest != i) {
    swap(arr, i, largest);
    heapify(arr, largest);
  }
}

function swap(arr, i, j) {
  var temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

function heapSort(arr) {
  buildMaxHeap(arr);

  for (var i = arr.length - 1; i > 0; i--) {
    swap(arr, 0, i);
    len--;
    heapify(arr, 0);
  }
  return arr;
}

let arr = [3, 44, 38, 5, 47, 15, 36, 26, 27, 12, 46, 4, 19, 50, 48];

console.log(heapSort(arr)); // [3,  4,  5, 12, 15, 19, 26, 27, 36, 38, 44, 46, 47, 48, 50]

八、计数排序

1、算法描述

  1. 找出待排序的数组中最大和最小的元素;
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
  3. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
  4. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。

2、图示

在这里插入图片描述

3、代码

function countingSort(arr, maxValue) {
  let bucket = newArray(maxValue + 1),
    sortedIndex = 0;
  (arrLen = arr.length), (bucketLen = maxValue + 1);

  for (let i = 0; i < arrLen; i++) {
    if (!bucket[arr[i]]) {
      bucket[arr[i]] = 0;
    }
    bucket[arr[i]]++;
  }

  for (let j = 0; j < bucketLen; j++) {
    while (bucket[j] > 0) {
      arr[sortedIndex++] = j;
      bucket[j]--;
    }
  }

  return arr;
}

九、桶排序

1、算法描述

  1. 设置一个定量的数组当作空桶
  2. 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  3. 对每个不是空的桶进行排序;
  4. 从不是空的桶里把排好序的数据拼接起来

2、图示

 

3、代码

function bucketSort(arr, bucketSize) {
  if (arr.length === 0) {
    return arr;
  }

  let minValue = arr[0];
  let maxValue = arr[0];
  for (let i = 1; i < arr.length; i++) {
    if (arr[i] < minValue) {
      minValue = arr[i]; // 输入数据的最小值
    } else if (arr[i] > maxValue) {
      maxValue = arr[i]; // 输入数据的最大值
    }
  }

  // 桶的初始化
  let DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5
  bucketSize = bucketSize || DEFAULT_BUCKET_SIZE;
  let bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1;
  let buckets = newArray(bucketCount);
  for (let i = 0; i < buckets.length; i++) {
    buckets[i] = [];
  }

  // 利用映射函数将数据分配到各个桶中
  for (let i = 0; i < arr.length; i++) {
    buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]);
  }

  arr.length = 0;
  for (let 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;
}

十、基数排序

1、算法描述

  1. 取得数组中的最大数,并取得位数;
  2. arr为原始数组,从最低位开始取每个位组成radix数组;
  3. 对radix进行计数排序(利用计数排序适用于小范围数的特点)

2、图示

在这里插入图片描述

3、代码

let counter = [];
function radixSort(arr, maxDigit) {
  let mod = 10;
  let dev = 1;
  for (let i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) {
    for (let j = 0; j < arr.length; j++) {
      let bucket = parseInt((arr[j] % mod) / dev);
      if (counter[bucket] == null) {
        counter[bucket] = [];
      }
      counter[bucket].push(arr[j]);
    }
    let pos = 0;
    for (let j = 0; j < counter.length; j++) {
      let value = null;
      if (counter[j] != null) {
        while ((value = counter[j].shift()) != null) {
          arr[pos++] = value;
        }
      }
    }
  }
  return arr;
}

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

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

相关文章

食品与疾病关系预测赛题

和鲸平台数据分析实战 题目&#xff1a;食品与疾病关系预测算法赛道 一、赛题描述 食品与疾病关系预测算法赛道 越来越多的证据表明&#xff0c;食物分子与慢性疾病之间存在关联甚至治疗关系。营养成分可能直接或间接地作用于人类基因组&#xff0c;并调节参与疾病风险和疾病…

php结课报告--会员注册管理系统

目录 1&#xff0e; 系统背景及意义 1 2&#xff0e; 系统的设计思路 1 2.1 数据库设计分析 1 2.2 功能模块设计分析 1 3&#xff0e; 程序功能测试及截图 1 3.1代码测试与功能演示 1 4&#xff0e; 总结与收获 6 1&#xff0e;系统背景及意义 随着现在时代得发展&#xff0c;…

【AI面试】NMS 与 Soft NMS 的辨析

往期文章&#xff1a; AI/CV面试&#xff0c;直达目录汇总【AI面试】L1 loss、L2 loss和Smooth L1 Loss&#xff0c;L1正则化和L2正则化 一、NMS 非极大值抑制&#xff08;Non-Maximum Suppression&#xff0c;NMS&#xff09;&#xff0c;并不是深度学习时期&#xff0c;目标…

VS项目配置常用的配置

背景随着学习使用VS的深入在项目配置使用一些相对路径是必不可少的,使用绝对路径是最简单的,但是加入你换了电脑或者别人拉取你的代码,就会发现通常会编译不过.因为项目配置使用了绝对路径.所以使用相对路径的好处就会体现.在VS项目配置有自己的一套配置,简单记录一下我使用到的…

mysql一主键uuid和自增的选择

文章目录 1.自增ID的优缺点1.1 优点1.2 缺点1.3 不适合以自增ID主键作为主键的情况2.UUID作为主键2.1 介绍2.2 优点2.3 缺点3.有序UUID作为主键3.1 介绍3.2 演示使用3.2.1 前提知识3.2.1.1 数据类型 - binary3.2.1.2 函数 - hex()3.2.1.3 函数 - unhex()3.2.2 数据库层3.2.3 JA…

蓝桥杯第十四届校内赛(第三期) C/C++ B组

一、填空题 &#xff08;一&#xff09;最小的十六进制 问题描述   请找到一个大于 2022 的最小数&#xff0c;这个数转换成十六进制之后&#xff0c;所有的数位&#xff08;不含前导 0&#xff09;都为字母&#xff08;A 到 F&#xff09;。   请将这个数的十进制形式作…

提升Mac使用性能的5大方法,CleanMyMacX 2023非常的好用哦~

近些年伴随着苹果生态的蓬勃发展&#xff0c;越来越多的用户开始尝试接触Mac电脑。然而很多人上手Mac后会发现&#xff0c;它的使用逻辑与Windows存在很多不同&#xff0c;而且随着使用时间的增加&#xff0c;一些奇奇怪怪的文件也会占据有限的磁盘空间&#xff0c;进而影响使用…

sql数据库常用操作指令

一、操作库-- 创建库create database db1;-- 创建库是否存在&#xff0c;不存在则创建create database if not exists db1;-- 查看所有数据库show databases;-- 查看某个数据库的定义信息 show create database db1; -- 修改数据库字符信息alter database db1 character set ut…

Istio Sidecar启动顺序 - 导致的应用容器网络不通

目录一、问题二、Istio 1.7及其之后版本的解决方案2.1 方式1&#xff1a;安装Istio时全局设置2.2 方式2&#xff1a;在应用Deployment通过annotation设置2.3 holdApplicationUntilProxyStarts启用效果三、Istio 1.7之前的解决方案一、问题 线上应用集成了Spring Cloud K8S Con…

HCIP实验1

实验要求 1 R6为isp, 接口IP地址均为公有地址;该设备只能配置IP地址&#xff0c;之后不能冉对其进行其他任何配置; 2 R1-R5为局域网&#xff0c;私有IP地址192.168.1.0/24&#xff0c; 请合理分配; 3 R1, R2, R4,各有两个环回地址; R5; R6各有一个环回地址;所有路由器上环回均…

2 GateWay工作流程+GateWay搭建

GateWay工作流程GateWay搭建 核心流程图如下&#xff1a; 核心概念&#xff1a; 客户端向 Spring Cloud Gateway 发出请求。如果Gateway Handler Mapping确定请求与路由匹配&#xff0c;则将其发送到Gateway Web Handler 处理程序。此处理程序通过特定于请求的Fliter链运行请求…

ARM uboot 的移植1-从三星官方 uboot 开始移植

一、移植初体验 1、直接编译三星移植版 uboot 尝试运行 (1) 复制到 linux 的源生目录下&#xff0c;然后解压开。 (2) 检查 Makefile 中的交叉编译工具链。 (3) 配置时使用&#xff1a;make smdkv210single_config&#xff0c;对应 include/configs/smdkv210single.h 头文件。…

力扣(LeetCode)430. 扁平化多级双向链表(2023.03.04)

你会得到一个双链表&#xff0c;其中包含的节点有一个下一个指针、一个前一个指针和一个额外的 子指针 。这个子指针可能指向一个单独的双向链表&#xff0c;也包含这些特殊的节点。这些子列表可以有一个或多个自己的子列表&#xff0c;以此类推&#xff0c;以生成如下面的示例…

javaWeb核心01-HTTPTomcatServlet

文章目录HTTP&Tomcat&Servlet1&#xff0c;Web概述1.1 Web和JavaWeb的概念1.2 JavaWeb技术栈1.2.1 B/S架构1.2.2 静态资源1.2.3 动态资源1.2.4 数据库1.2.5 HTTP协议1.2.6 Web服务器1.3 Web核心课程安排2, HTTP2.1 简介2.2 请求数据格式2.2.1 格式介绍2.2.2 实例演示2.…

区块链学习

hash函数 一种算法任意长度的二进制数据映射为固定长度的二进制数据 hash函数的特点 确定性------对同一个输入数据每次都能得到相同的结果单向性------对一个数据可以很容易计算出hash值&#xff0c;但是对于一个hash值非常难反推出数据隐秘性------没有可行的方法算出hash…

OpenCV入门(三)快速学会OpenCV2图像处理基础

OpenCV入门&#xff08;三&#xff09;快速学会OpenCV2图像处理基础 1.颜色变换cvtColor imgproc的模块名称是由image&#xff08;图像&#xff09;和process&#xff08;处理&#xff09;两个单词的缩写组合而成的&#xff0c;是重要的图像处理模块&#xff0c;主要包括图像…

VSCode问题记录

20230304 - 0. 引言 这几年的编程方式还真是各种变化&#xff0c;从一开始直接VIM&#xff0c;到后面使用jupyter进行机器学习相关&#xff0c;然后再过渡到vim的形式并加以tmux批量化&#xff0c;最后去年使用了vscode作为IDE。随着工具的变化&#xff0c;那么很多习惯也都随…

PyQGIS自定义应用程序打包

路径准备ps:打包时需要根据自己的安装路径进行相应修改QGIS3.22.16的安装路径&#xff1a;D:\QGIS3.22.16QGIS3.22.16中python-qgis.bat的路径&#xff1a;D:\QGIS3.22.16\bin\python-qgis-ltr.bat准备打包的工程所在目录&#xff1a;E:\Crater_DamageEstimation0303安装pyinst…

Python基础—文件操作

Python基础—文件操作 文件操作 文件是指为了重复使用或长期使用的目的&#xff0c;以文本或二进制形式存放于外部存储器&#xff08;硬盘、U盘、光盘等&#xff09;中的数据保存形式&#xff0c;文件是信息交换的重要途径&#xff0c;也是利用程序解决实际问题的重要媒介。 …

网络编程面试相关内容

1.什么是网络编程网络编程的本质是多台计算机之间的数据交换。数据传递本身没有多大的难度&#xff0c;不就是把一个设备中的数据发送给其他设备&#xff0c;然后接受另外一个设备反馈的数据。现在的网络编程基本上都是基于请求/响应方式的&#xff0c;也就是一个设备发送请求数…