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

MySQL--日志管理

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、日志简介 MySQL日志主要分为4类&#xff0c;使用这些日志文件&#xff0c;可以查看MySQL内部发生的事情。这4类日志分别是: 错误日志&#xff1…...

【Nuxt】内置组件和全局样式使用

内置组件 Nuxt3框架也提供一些内置的组件&#xff0c;常用的如下&#xff1a; SEO组件&#xff1a;Html、Body、Head、Title、Meta、Style、Link、NoScript、BaseNuxtWelcome:欢迎页面组件&#xff0c;该组件是nuxt/ui的部分NuxtLayout:是Nuxt自带的页面布局组件NuxtPage:是N…...

Java中spring boot validation 自定义注解使用

创建一个注解 Target({ElementType.FIELD})//需要写注解的三三个要素 Retention(RUNTIME) Documented Constraint(validatedBy {IsSystemYesNoVaildation.class})//绑定 在这里会报错 你需要去实现 public interface IsSystemYesNo {String message() default "数据字典&…...

Android笔试面试题AI答之广播(1)

文章目录 1.简述广播的分类和使用场景 &#xff1f;一、广播分类二、使用场景举例总结 2.广播的两种注册方式的区别&#xff1f;1. 注册位置与方式2. 生命周期与持久性3. 接收广播的时机4. 安全性与权限5. 优先级与有序广播总结 3.简述广播发送和接收的原理 &#xff1f;一、广…...

微软商店无法加载,检查你的连接-解决方案

微软商店默认直连国内的服务器。 如果有代理&#xff0c;关闭代理就可以恢复网络了。 但是我就是想用代理&#xff0c;我感觉代理更快&#xff0c; 搜索了很多办法&#xff0c;都没有生效。 然后我在哔哩哔哩的视频下方&#xff0c;看到大家留言&#xff0c;测试了一下&#x…...

数据结构实验报告-树与二叉树

桂 林 理 工 大 学 实 验 报 告 一、实验名称&#xff1a; 实验6 树和二叉树 二、实验内容&#xff1a; 1.编写二叉树的递归遍历算法&#xff0c;实现:给定一棵二叉树的“扩展先序遍历序列”&#xff0c;创建这棵二叉树。 (1)输出二叉树的先序遍历的结点序列。 (2)输出二…...

基于Django+MySQL球馆场地预约系统的设计与实现(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…...

8 MQTT

8 MQTT 1、相关概念2、MQTT的操作过程3、MQTT协议3.1 固定报文3.2 连接报文3.3 确认连接请求3.4 构造订阅报文3.5 订阅确认报文3.6 发布报文3.7 其他报文 1、相关概念 MQTT [1] 全名为Message Queuing Telemetry Transport&#xff0c;是一种基于TCP/IP协议上传输的轻量级通信…...

【文件系统】抽象磁盘的存储结构 CHS寻址法 | sector数组 | LAB数组

目录 1.为什么要抽象 2.逻辑抽象_版本1 2.1sector数组 ​2.2index转化CHS 3.逻辑抽象_版本2 3.1LBA数组 3.2LAB下标转化sector下标 文件其实就是在磁盘中占有几个扇区的问题❗文件是很多个sector的数组下标❗文件是有很多块构成的❗❗文件由很多扇区构成------>文件…...

基于python旅游推荐系统(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…...