当前位置: 首页 > 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自制随机函数来…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...