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

Javascript常见算法详解

在JavaScript(JS)中,常见的算法涵盖了多个领域,从基础的数组操作到更复杂的排序、搜索和数据结构算法。下面是一些在JS中常见的算法示例:

1. 排序算法

Java排序算法-CSDN博客

  • 冒泡排序(Bubble Sort):通过重复遍历要排序的数列,比较每对相邻元素的值,若发现顺序错误则交换之。应用场景:冒泡排序由于其实现简单,适合小规模数据或基本有序的数据排序。
function bubbleSort(arr) {  const len = arr.length;  for (let i = 0; i < len - 1; 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;  
}  
const nums = [4, 5, 2, 7, 8];  
console.log(bubbleSort(nums)); // [2, 4, 5, 7, 8]
  • 选择排序(Selection Sort):在要排序的一组数中,选出最小(或最大)的一个数与第一个位置的数交换;然后在剩下的数当中再找最小(或最大)的与第二个位置的数交换,依此类推。应用场景:选择排序同样适合小规模数据的排序。
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;  
}  
const nums = [4, 5, 2, 7, 8];  
console.log(selectionSort(nums)); // [2, 4, 5, 7, 8]
  • 插入排序(Insertion Sort):通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。小规模数据或基本有序的数据。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,找到排序位置后,需要将已排序元素逐步向后挪位,为新元素提供插入空间。

function insertionSort(arr) {  for (let i = 1; i < arr.length; i++) {  let key = arr[i]; // 当前需要插入的元素  let j = i - 1;  // 将大于key的元素向后移动一位  while (j >= 0 && arr[j] > key) {  arr[j + 1] = arr[j];  j = j - 1;  }  arr[j + 1] = key; // 插入key到正确的位置  }  return arr;  
}  // 示例  
const nums = [12, 11, 13, 5, 6];  
console.log(insertionSort(nums)); // 输出: [5, 6, 11, 12, 13]
  • 归并排序Merge Sort):分治法的一个典型应用,将已有序的子序列合并,得到完全有序的序列。它将一个数组分成两半,对每半部分递归地应用归并排序,然后将排序好的两半合并成一个有序数组。归并排序的主要优点是稳定、效率高(平均和最坏时间复杂度均为O(n log n)),并且易于实现并行化。
function mergeSort(arr) {  if (arr.length < 2) {  // 基本情况:如果数组只有一个元素或为空,则直接返回该数组  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 = [], leftIndex = 0, 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++;  }  }  // 如果左部分还有剩余元素,则将它们添加到结果数组中  while (leftIndex < left.length) {  result.push(left[leftIndex]);  leftIndex++;  }  // 如果右部分还有剩余元素,则将它们添加到结果数组中  while (rightIndex < right.length) {  result.push(right[rightIndex]);  rightIndex++;  }  return result;  
}  // 示例  
const nums = [38, 27, 43, 3, 9, 82, 10];  
console.log(mergeSort(nums)); // 输出: [3, 9, 10, 27, 38, 43, 82]
  • 快速排序(Quick Sort):是一种高效的排序算法,采用分而治之的策略来把一个序列分为较小和较大的两个子序列,然后递归地排序两个子序列。在JavaScript中,快速排序的实现通常涉及选择一个“基准”元素(pivot),然后将数组分成两个子数组:一个包含所有小于基准值的元素,另一个包含所有大于基准值的元素。最后,递归地对这两个子数组进行快速排序。
    应用场景:快速排序适用于大规模数据的排序,平均时间复杂度为O(n log n)。
function quickSort(arr) {  if (arr.length <= 1) {  return arr;  }  const pivot = arr[0];  const left = [];  const right = [];  for (let i = 1; i < arr.length; i++) {  if (arr[i] < pivot) {  left.push(arr[i]);  } else {  right.push(arr[i]);  }  }  return [...quickSort(left), pivot, ...quickSort(right)];  
}  
const nums = [4, 5, 2, 7, 8];  
console.log(quickSort(nums)); // [2, 4, 5, 7, 8]

2. 搜索算法

  • 线性搜索(Linear Search):逐个检查每个元素,直到找到所需的特定元素为止。
function linearSearch(arr, target) {  for (let i = 0; i < arr.length; i++) {  if (arr[i] === target) {  // 找到目标值,返回其索引  return i;  }  }  // 未找到目标值,返回-1  return -1;  
}  // 示例  
const arr = [3, 5, 7, 9, 11, 13, 15];  
const target = 9;  
console.log(linearSearch(arr, target)); // 输出: 3  const missingTarget = 10;  
console.log(linearSearch(arr, missingTarget)); // 输出: -1
  • 二分搜索(Binary Search):在有序数组中查找某一特定元素的搜索算法,搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。

function binarySearch(arr, target) {  let left = 0;  let right = arr.length - 1;  while (left <= right) {  let mid = Math.floor((left + right) / 2);  if (arr[mid] === target) {  // 找到目标值,返回其索引  return mid;  } else if (arr[mid] < target) {  // 目标值在中间值的右侧,调整左边界  left = mid + 1;  } else {  // 目标值在中间值的左侧,调整右边界  right = mid - 1;  }  }  // 未找到目标值,返回-1  return -1;  
}  // 示例  
const arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];  
const target = 7;  
console.log(binarySearch(arr, target)); // 输出: 3  const missingTarget = 10;  
console.log(binarySearch(arr, missingTarget)); // 输出: -1

3. 数组和字符串操作

  • 反转数组:通过交换首尾元素的方式实现。

反转数组是一个基础且常见的算法问题,可以通过多种编程语言实现。在JavaScript中,我们已经知道有一个内置的reverse()方法可以直接用来反转数组,但如果你想要自己实现一个反转数组的算法,你可以通过交换数组的首尾元素,然后向中心移动,直到到达数组的中间位置。

下面是一个使用JavaScript实现的反转数组算法的例子:

function reverseArray(arr) {  let left = 0; // 左指针  let right = arr.length - 1; // 右指针  while (left < right) {  // 交换左右指针所指的元素  let temp = arr[left];  arr[left] = arr[right];  arr[right] = temp;  // 移动指针  left++;  right--;  }  // 由于是在原数组上进行操作,所以不需要返回新的数组  // 但为了演示,我们可以返回原数组或者null,表示操作已完成  return arr;  
}  // 示例  
let arr = [1, 2, 3, 4, 5];  
reverseArray(arr);  
console.log(arr); // 输出: [5, 4, 3, 2, 1]

这个算法的时间复杂度是O(n/2),但通常我们将其简化为O(n),因为n/2和n在算法分析中属于同一数量级。空间复杂度是O(1),因为我们只是使用了常量级别的额外空间(几个变量)来执行操作,而没有使用与输入规模成比例的额外空间。

需要注意的是,这个算法直接修改了原数组。如果你不想修改原数组,你可以先复制一份数组,然后在复制的数组上进行反转操作。例如:

function reverseArrayWithoutMutating(arr) {  let copy = [...arr]; // 使用扩展运算符创建数组的一份浅拷贝  let left = 0;  let right = copy.length - 1;  while (left < right) {  let temp = copy[left];  copy[left] = copy[right];  copy[right] = temp;  left++;  right--;  }  return copy; // 返回反转后的新数组  
}  // 示例  
let arr = [1, 2, 3, 4, 5];  
let reversedArr = reverseArrayWithoutMutating(arr);  
console.log(reversedArr); // 输出: [5, 4, 3, 2, 1]  
console.log(arr); // 输出: [1, 2, 3, 4, 5](原数组未改变)
  • 字符串去重:使用Set或遍历字符串,利用对象记录字符出现情况,实现去重。
function uniqueCharsInOrder(str) {  // 创建一个 Set 对象,用于存储已经遇到的字符  let seen = new Set();  // 初始化一个空字符串,用于存放去重后的结果  let result = '';  // 遍历原字符串中的每个字符  for (let char of str) {  // 检查当前字符是否已经在 Set 中  if (!seen.has(char)) {  // 如果没有,则将其添加到 Set 中,并追加到结果字符串的末尾  seen.add(char);  result += char;  }  // 如果字符已经在 Set 中,则跳过它,不添加到结果字符串中  }  // 返回去重后且保持原始顺序的字符串  return result;  
}  // 示例  
console.log(uniqueCharsInOrder('hello world!')); // 输出: "helo wrd!"
  • 子字符串搜索:使用indexOfincludes等方法。

indexOf() 方法

indexOf() 方法用于返回在父字符串中首次出现的子字符串的索引,如果没有找到则返回 -1。这个方法对于需要知道子字符串具体位置的场景非常有用。

let str = "Hello, world!";  
let index = str.indexOf("world");  
console.log(index); // 输出: 7  let fromIndex = 8;  
let notFoundIndex = str.indexOf("world", fromIndex);  
console.log(notFoundIndex); // 输出: -1,因为从索引8开始找不到"world"

includes() 方法

includes() 方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。这个方法对于只需要知道子字符串是否存在,而不需要知道其位置的场景很有用。

let str = "Hello, world!";  
let found = str.includes("world");  
console.log(found); // 输出: true  let notFound = str.includes("universe");  
console.log(notFound); // 输出: false  let fromPosition = 7;  
let foundAtPosition = str.includes("world", fromPosition);  
console.log(foundAtPosition); // 输出: true,即使起始位置是7,"world"依然从该位置开始  // 注意:如果fromIndex大于字符串长度,则includes方法返回false  
let fromIndexTooHigh = str.includes("world", 20);  
console.log(fromIndexTooHigh); // 输出: false

4. 动态规划

  • 斐波那契数列:经典的动态规划问题,每个数是前两个数的和。

  • 最长公共子序列(LCS):寻找两个序列共有的最长子序列的问题。

5. 图论算法

  • 深度优先搜索(DFS):沿着树的深度遍历树的节点,尽可能深地搜索树的分支。

  • 广度优先搜索(BFS):从根节点开始,沿着树的宽度遍历树的节点。

6. 递归算法

递归算法在JS中非常常见,如计算阶乘、遍历文件目录等。

7. 数据结构相关算法

  • 栈和队列的基本操作:如入栈(入队)、出栈(出队)、查看栈顶(队首)等。

  • 链表操作:包括创建链表、添加节点、删除节点、反转链。表等

相关文章:

Javascript常见算法详解

在JavaScript&#xff08;JS&#xff09;中&#xff0c;常见的算法涵盖了多个领域&#xff0c;从基础的数组操作到更复杂的排序、搜索和数据结构算法。下面是一些在JS中常见的算法示例&#xff1a; 1. 排序算法 Java排序算法-CSDN博客 冒泡排序&#xff08;Bubble Sort&#x…...

MySQL数据管理 - 查询语句

文章目录 查询数据1 查询指定列2 条件查询3 合并查询4 模糊查询5 聚合函数查询6 对值进行排序7 分组查询8 分页查询9 数据库关联查询1 内连接 INNER JOIN2 LEFT JOIN3 右连接 10 数据库子查询参考 查询数据 数据库最常用的操作就是查询&#xff0c;也是数据操作的基础&#xf…...

经典图论算法回顾之Bellman-Ford算法

Dijkstra最短路径算法存在的一个问题是不能处理负权图&#xff08;详见&#xff1a;经典图论算法回顾之Dijkstra算法。今天要回顾的Bellman-Ford算法&#xff08;wikipedia&#xff1a;Bellman–Ford algorithm&#xff09;可以求出有负权图的最短路径&#xff0c;并可以对最短…...

LinuxC++(10):调用可执行程序

认识system函数 可以直接用system在代码中实现调用shell命令 /bin/ls -l /tmp表示执行ls -l命令&#xff0c;打开/tmp地址 而前面的/bin/表示这是shell命令&#xff0c;不可少&#xff0c;可以认为&#xff0c;/bin/后面的就是等价于shell里面输入的命令。 然后&#xff0c;cou…...

C语言指针·高级用法超详解(指针运算、野指针、悬空指针、void类型指针、二级以及多级指针)

目录 1. 指针的运算 2. 野指针和悬空指针 2.1 野指针 2.2 悬空指针 3. void类型指针 4. 二级指针和多级指针 4.1 命名规则 4.2 作用 4.2.1 二级指针可以操作一级指针记录的地址 4.2.2 利用二级指针获取变量中记录的数据 1. 指针的运算 文章开始前可以先了…...

SQL注入:MySQL元数据库,外网实战手工SQL注入

MySQL元数据库 MySQL的元数据库是一组特殊的数据库&#xff0c;用于存储MySQL服务器的元数据信息&#xff0c;在sql注入中较为常用为以下两种元数据库&#xff1a; information_schema&#xff1a;这个数据库包含了MySQL服务器上所有其他数据库的元数据信息。例如数据库名、表…...

接口与抽象类有什么区别

接口&#xff1a;只能包含抽象方法&#xff0c;成员变量只能是public static final 类型 是对行为的抽象 先约定再接口再实现 抽象类&#xff1a;包含成员变量和一般方法和抽象方法&#xff0c;当继承时&#xff0c;子类必须实现抽象类中的抽象方法...

【时时三省】unity test 测试框架 使用 code blocks 移植(核心文件:unity.c, unity_fixture.c)

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 目录 1&#xff0c;移植介绍 2&#xff0c;使用 Code::Blocks 17.12 创建工程 3&#xff0c;搬移文件入工程目录 4&#xff0c;更改代码 5&#xff0c;向工程添加文件 6&#xff0c;运…...

安装Docker以及安装过程中的错误解决

一、纯享版教程&#xff0b;操作截图 环境&#xff1a;centOs 7 FinalShell &#xff01;&#xff01;&#xff01;此教程针对第一次安装docker的友友&#xff0c;如果已经安装过且报错的朋友&#xff0c;请移步报错合集。 1.卸载旧版本&#xff08;无论是否安装过都建议执…...

PXE实验

实验前准备 关闭VMware的dhcp 点击 编辑 点击 虚拟网络编辑器 选择 NAT模式 将dhcp取消勾选 准备两台虚拟机 一台试验机&#xff0c;&#xff08;网络环境正常并且有图形化的界面的rhel7&#xff09; 一台测试机 init 5 --------------> 开启图形化界面 如…...

Spring - 解析 统一数据格式返回以及统一异常处理

接上篇文章的统一数据格式返回… 文章目录 1. 统一异常处理1.1 使用 2. 统一数据返回和统一异处理是怎么实现的2.1 initHandleAdapters2.2 initHandleExceptionResolvers 1. 统一异常处理 1.1 使用 统一异常处理的两个关键的注解是ControllerAdvice ExceptionHandler Contro…...

用Manim实现——计算和绘制图形下方区域

用Manim实现——计算和绘制图形下方区域 get_area 函数 get_area是一个用于计算和绘制图形下方区域的函数&#xff0c;常用于图形动画库&#xff08;如 Manim&#xff09; get_area(graph, x_rangeNone, color(ManimColor(#58C4DD),ManimColor(#83C167)), opacity0.3, bounde…...

MySQL 保姆级教程(十五): 组合查询

第 17 章 组合查询 17.1 组合查询 MySQL 允许执行多个查询&#xff08;多条 SELECT 语句&#xff09;&#xff0c;并将结果作为单个查询集返回 17.2 创建组合查询 可用 UNION 操作符来组合数条 SQL 查询 17.2.1 使用 UNION 输入: SELECT user.USER FROM user UNION SELEC…...

《动手做科研》06. 如何产生新的研究想法

地址链接:《动手做科研》06. 如何产生新的研究想法 欢迎加入我的知识星球&#xff0c;定期分享AI论文干货知识&#xff01; 导读: 提出好的研究想法是相当困难的&#xff0c;特别是当你刚接触一个领域时——这需要对文献中的空白有所了解。然而&#xff0c;产生研究想法的过程可…...

【Kubernetes】Deployment 的状态

Deployment 的状态 Deployment 控制器在整个生命周期中存在 3 3 3 种状态&#xff1a; 已完成&#xff08;Complete&#xff09;进行中&#xff08;Progressing&#xff09;失败&#xff08;Failed&#xff09; 通过观察 Deployment 的当前特征&#xff0c;可以判断 Deploym…...

新手学习Gazebo+ros仿真控制小车-----易错和自己理解

赵虚左老师讲的很详细&#xff0c;这里只是理一下思路&#xff0c;说下突然出现“新”概念之间的关系。 urdf文件:里面是配置模型的&#xff0c;既有模型的位置、尺寸、颜色&#xff0c;也包含复杂的物理模型信息比如&#xff1a;转动惯量&#xff0c;碰撞box大小等等&#xff…...

jdbc(mysql)

1.概述 jdbc&#xff1a;java database connection&#xff08;java与数据库连接&#xff09; java可以连接不同数据库&#xff0c;不同数据库连接细节不同&#xff0c;具体细节都由数据库自己实现 由java设计出一系列连接数据库的接口规范&#xff0c;然后由不同的数据库开发…...

【Linux】搜索log在哪个文件中执行的方法

在Linux中&#xff0c;如果你需要找到包含特定文本&#xff08;比如一段log&#xff09;的文件&#xff0c;你可以使用grep命令结合一些其他工具来实现这一目的。这里有几个方法可以帮助你找到包含特定log内容的文件。 1. 使用grep直接在特定目录或文件中搜索 如果你知道log大…...

web小游戏开发:2048(完)移动操作及动画效果

web小游戏开发:2048(完)移动操作及动画效果 添加随机数字游戏开始时的初始化显示分数移动和合并获取行列元素下标记录移动轨迹完整的 js小结添加随机数字 书接前文,我们在前边定义了一个 move 方法,暂时先往后放放。 在我们已经初始化好的界面上,我们需要先制作一个出现…...

Redis学习笔记——第20章 Lua脚本

第20章 Lua脚本 20.1 创建并修改Lua环境 20.1.1 创建Lua环境 服务器创建一个新的基本的Lua环境 20.1.2 载入函数库 修改Lua环境&#xff0c;载入一些库函数 20.1.3 创建redis全局表格 全局变量&#xff0c;支持在Lua脚本中执行redis命令 20.1.4 使用redis自制随机函数来…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

【kafka】Golang实现分布式Masscan任务调度系统

要求&#xff1a; 输出两个程序&#xff0c;一个命令行程序&#xff08;命令行参数用flag&#xff09;和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽&#xff0c;然后将消息推送到kafka里面。 服务端程序&#xff1a; 从kafka消费者接收…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...