JavaScript中的常见算法

一.排序算法

1.冒泡排序


        冒泡排序比较所有相邻的两个项,如果第一个比第二个大,则交换它们。元素项向上移动至 正确的顺序,就好像气泡升至表面一样。

function bubbleSort(arr) {const { length } = arrfor (let i = 0; i < length - 1; i++) {for (let j = 0; j < length - i - 1; j++) {if (arr[j] > arr[j + 1]) {[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]}}}return arr
}arr = [3, 2, 5, 4, 7, 1]
console.log(bubbleSort(arr));  //[1, 2, 3, 4, 5, 7]

2.选择排序


         选择排序算法是一种原址比较排序算法。选择排序大致的思路是找到数据结构中的最小值并 将其放置在第一位,接着找到第二小的值并将其放在第二位,以此类推。

function selectSort(arr) {const { length } = arrlet minfor (let i = 0; i < length - 1; i++) {min = ifor (let j = i; j < length; j++) {if (arr[j] < arr[min]) {min = j}}if (min !== i) {[arr[i], arr[min]] = [arr[min], arr[i]]}}return arr
}

3.插入排序 


如图所示,只可意会不可言传 

function insertSort(arr) {const { length } = arrlet tempfor (let i = 1; i < length; i++) {temp = arr[i]let j = iwhile (j > 0 && arr[j - 1] > temp) {arr[j] = arr[j - 1]j--}arr[j] = temp}return arr
}

4.归并排序 


        归并排序是一种分而治之算法。其思想是将原始数组切分成较小的数组,直到每个小数组只 有一个位置,接着将小数组归并成较大的数组,直到最后只有一个排序完毕的大数组。

 图片详解:

function mergeSort(array) {if (array.length > 1) {const {length} = array;const middle = Math.floor(length / 2);const left = mergeSort(array.slice(0, middle));const right = mergeSort(array.slice(middle, length));array = merge(left, right);}return array;
}function merge(left, right) {let i = 0;let j = 0;const result = [];while (i < left.length && j < right.length) {result.push(left[i] < right[j] ? left[i++] : right[j++]);console.log(result)//先push ,再++}return result.concat(i < left.length ? left.slice(i) : right.slice(j));
}

例如,如果 left = [3, 4]right = [1, 2],那么 merge 函数会按以下步骤操作:

  • 比较 left[0]right[0](3 和 1),因为 1 < 3,所以将 1 添加到 result,打印 [1]
  • 然后比较 left[0]right[1](3 和 2),因为 2 < 3,所以将 2 添加到 result,打印 [1, 2]
  • 由于 right 已经被完全遍历,将 left 剩余的元素(3 和 4)添加到 result,最终 result[1, 2, 3, 4]

 5.快速排序


         确立基准元素,根据其它元素与基准元素的大小比较,大的分为一组,小的分为一组,再在连接字符串的时候递归调用相应的方法,直至碰到递归调用的结束条件。

function quickSort(arr) {const { length } = arr//结束条件if (length < 2) {return arr}let base = arr[0]let minArr = arr.slice(1).filter(item => item <= base)let maxArr = arr.slice(1).filter(item => item >= base)return quickSort(minArr).concat(base).concat(quickSort(maxArr))
}

6.计数排序


        计数排序使用一个用来存储每个元素在原始数组中出现次数的临时数组。在所有元素都计数完成后,临时数组已排好序并可迭代以构建排序 后的结果数组。  

//缺点是浪费数组空间,最好是在要排序的数字比较连续紧凑的时候使用
function countSort(arr) {if (arr.length < 2) {return arr}const maxValue = Math.max(...arr)const counts = new Array(maxValue + 1)//让数组的值作为新数组的索引值,再进行计数arr.forEach(item => {if (!counts[item]) {counts[item] = 0}counts[item]++});let newArr = []let sortIndex = 0counts.forEach((item, index) => {while (item > 0) {newArr[sortIndex++] = indexitem--}})return newArr
}

7.桶排序

         桶排序(也被称为箱排序)也是分布式排序算法,它将元素分为不同的桶(较小的数组), 再使用一个简单的排序算法,例如插入排序(用来排序小数组的不错的算法),来对每个桶进行 排序。然后,它将所有的桶合并为结果数组。  

function bucketSort(arr, bucketSize = 3) {if (arr.length < 2) {return arr}//根据数字的个数和大小,以及桶的容量创建数量合适的桶,将各数字分配到相应的桶里const buckets = createBuckets(arr, bucketSize)//调用相应的方法并返回成功排序了的数组return sortBucketsElement(buckets)
}function createBuckets(arr, bucketSize) {let maxValue = Math.max(...arr)let minValue = Math.min(...arr)const bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1const buckets = [...Array(bucketCount)].map(() => [])for (let i = 0; i < arr.length; i++) {const bucketIndex = Math.floor((maxValue - minValue) / bucketSize)buckets[bucketIndex].push(arr[i])}return buckets
}function sortBucketsElement(buckets) {const sortArr = []for (let i = 0; i < buckets.length; i++) {if (buckets[i]) {let newBucket = insertSort(buckets[i])sortArr.push(...newBucket)}}return sortArr}function insertSort(arr) {const { length } = arrlet tempfor (let i = 1; i < length; i++) {temp = arr[i]let j = iwhile (j > 0 && arr[j - 1] > temp) {arr[j] = arr[j - 1]j--}arr[j] = temp}return arr
}console.log(bucketSort([5, 4, 3, 2, 6, 1, 7, 10, 9, 8]));//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

8. 基数排序


         基数排序也是一个分布式排序算法,它根据数字的有效位或基数(这也是它为什么叫基数排 序)将整数分布到桶中。简单来说是根据最大数的位数来确定排序的次数,排序的时候分别从个位,十位,百位等分别进行排序。

function radixSort(arr) {const base = 10let divider = 1let max = Math.max(...arr)while (divider <= max) {const buckets = [...Array(10)].map(() => [])for (let i of arr) {buckets[Math.floor(i / divider) % base].push(i)}arr = [].concat(...buckets)console.log(arr);divider *= 10}return arr
}

二.搜索算法 

1.顺序搜索

        顺序或线性搜索是最基本的搜索算法。它的机制是,将每一个数据结构中的元素和我们要找 的元素做比较。顺序搜索是最低效的一种搜索算法。

function search(arr, value) {for (let i = 0; i < arr.length; i++) {if (value === arr[i]) {return i}}return -1
}

2. 二分搜索

function binarySearch(find, arr, start, end) {start = start || 0end = end || arr.length - 1arr = quickSort(arr)if (start <= end && find >= arr[start] && find <= arr[end]) {if (find === arr[start]) {return start}if (find === arr[end]) {return end}let mid = Math.ceil((start + end) / 2)if (arr[mid] === find) {return mid} else if (arr[mid] > find) {return binarySearch(find, arr, start, mid - 1)} else {return binarySearch(find, arr, mid + 1, end)}}return -1
}function quickSort(arr) {const { length } = arrif (length < 2) {return arr}let base = arr[0]let minArr = arr.slice(1).filter(item => item <= base)let maxArr = arr.slice(1).filter(item => item >= base)return quickSort(minArr).concat(base).concat(quickSort(maxArr))
}

3.内插搜索 

        内插搜索是改良版的二分搜索。二分搜索总是检查 mid 位置上的值,而内插搜索可能会根 据要搜索的值检查数组中的不同地方。

//适合数值分布比较均匀的数组
function insertSearch(find, arr, start, end) {start = start || 0end = end || arr.length - 1arr = quickSort(arr)if (start <= end && find >= arr[start] && find <= arr[end]) {if (find === arr[start]) {return start}if (find === arr[end]) {return end}let mid = start + Math.floor((find - arr[start]) / (arr[end] - arr[start]) * (end - start))if (arr[mid] === find) {return mid} else if (arr[mid] > find) {return insertSearch(find, arr, start, mid - 1)} else {return insertSearch(find, arr, mid + 1, end)}}return -1
}function quickSort(arr) {const { length } = arrif (length < 2) {return arr}let base = arr[0]let minArr = arr.slice(1).filter(item => item <= base)let maxArr = arr.slice(1).filter(item => item >= base)return quickSort(minArr).concat(base).concat(quickSort(maxArr))
}

 三.随机算法(洗牌算法)

        迭代数组,从最后一位开始并将当前位置和一个随机位置进行交换。这个随机位置比当前位置小。这样,这个算法可以保证随机过的位置不会再被随机一次。

function shuffleArray(array) {let n = array.lengthlet randomwhile (n != 0) {//对非负数进行向下取整random = (Math.random() * n--) >>> 0;[arr[n], arr[random]] = [arr[random], arr[n]]}
}

四.算法设计

1.分而治之

分而治之算法可以分成三个部分。

(1) 分解原问题为多个子问题(原问题的多个小实例)。

(2) 解决子问题,用返回解决子问题的方式的递归算法。递归算法的基本情形可以用来解决子 问题。

(3) 组合这些子问题的解决方式,得到原问题的解。

2.动态规划 

 2.1背包问题

背包问题是一个组合优化问题。它可以描述如下:给定一个固定大小、能够携重量 W 的背 包,以及一组有价值和重量的物品,找出一个最佳解决方案,使得装入背包的物品总重量不超过 W,且总价值最大。  

function knapSack(weights, values, w) {let n = weights.length - 1let f = [[]]for (let j = 0; j <= w; j++) {if (j < weights[0]) {f[0][j] = 0} else {f[0][j] = values[0]}}for (let j = 0; j <= w; j++) {for (let i = 1; i <= n; i++) {if (!f[i]) {f[i] = []}if (j < weights[i]) {f[i][j] = f[i - 1][j]} else {f[i][j] = Math.max(f[i - 1][j], f[i - 1][j - weights[i]] + values[i])}}}return f[n][w]
}console.log(knapSack([2, 2, 6, 5, 4], [6, 3, 5, 4, 6], 10)); 

2.2找出最长公共子序列

找出两个字符 串序列的最长子序列的长度。最长子序列是指,在两个字符串序列中以相同顺序出现,但不要求 连续(非字符串子串)的字符串序列。  

 

function LCS(str1, str2) {var m = str1.lengthvar n = str2.lengthvar dp = [new Array(n + 1).fill(0)] //第一行全是0console.log(dp);for (var i = 1; i <= m; i++) { //一共有m+1行dp[i] = [0] //第一列全是0for (var j = 1; j <= n; j++) { //一共有n+1列if (str1[i - 1] === str2[j - 1]) {//注意这里,str1的第一个字符是在第二列中,因此要减1,str2同理dp[i][j] = dp[i - 1][j - 1] + 1 //对角+1} else {dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])}}}let res = printLCS(dp, str1, str2, m, n)return dp[m][n];
}function printLCS(dp, str1, str2, i, j) {if (i === 0 || j === 0) {return ''}if (str1[i - 1] === str2[j - 1]) {return printLCS(dp, str1, str2, i - 1, j - 1) + str1[i - 1]} else {if (dp[i][j - 1] > dp[i - 1][j]) {return printLCS(dp, str1, str2, i, j - 1)} else {return printLCS(dp, str1, str2, i - 1, j)}}}console.log(LCS("abcadf", "acbaed")) //4

3.贪心算法

 在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的仅是在某种意义上的局部最优解。贪心算法不是对所有问题都能得到整体最优解,但对范围相当广泛的许多问题他能产生整体最优解或者是整体最优解的近似解。

function tanxin(capacity, weights, values) {let list = []let select = []let total = 0for (let i = 0; i < weights.length; i++) {list.push({num: i + 1,weight: weights[i],value: values[i],rate: values[i] / weights[i]})}list.sort((a, b) => b.rate - a.rate) //降序for (let j = 0; j < list.length; j++) {let item = list[i]if (item.weight <= capacity) {select.push({num: item.num,weight: item.weight,value: item.value,rate: 1})total = total + item.valuecapacity = capacity - item.weight} else if (item.capacity > capacity && capacity > 0) {let rate = capacity / item.weightselect.push({num: item.num,weight: item.weight * rate,value: item.value * rate,rate})total = total + item.value * ratebreak} else {break}}return { select, total }
}

 4.回溯算法

 回溯法采用试错的思想,它尝试分步的去解决一个问题。在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。

 给定一个 二维字符网格 board 和一个字符串单词 word
如果 word 存在于网格中,返回 true ;否则,返回 false
单词必须按照字母顺序,通过相邻的单元格内的字母构成
**二维数组:** board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]],
**目标:** word = "ABCCED"

function exist(board, word) {let row = board.length;  //行let col = board[0].length;  //列for (let i = 0; i < row; i++) {for (let j = 0; j < col; j++) {const ret = find(i, j, 0);if (ret) {return ret;}}}return false;function find(r, c, cur) {if (r >= row || r < 0) return false;if (c >= col || c < 0) return false;if (board[r][c] !== word[cur]) return false;if (cur == word.length - 1) return true;let letter = board[r][c];board[r][c] = null;const ret =find(r - 1, c, cur + 1) ||find(r + 1, c, cur + 1) ||find(r, c - 1, cur + 1) ||find(r, c + 1, cur + 1);//用null做标记是避免重复查找board[r][c] = letter;return ret;}
};

 五.总结

        还有诸多算法没有详细解读,随着自己的学习慢慢补充吧。 

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

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

相关文章

详解自定义类型:枚举与联合体!

目录 ​编辑 一、枚举类型 1.枚举类型的声明 2.枚举类型的优点 3.枚举类型的使用 二、联合体类型(共用体&#xff09; 1.联合体类型的声明 2.联合体的特点 3.相同成员的结构体和联合体的对比 4.联合体大小的计算 5.用联合体判断大小端 三.完结散花 悟已往之不谏&…

深入浅出了解谷歌「Gemini大模型」发展历程

Google在2023年12月官宣了Gemini模型&#xff0c;随后2024年2月9日才宣布Gemini 1.0 Ultra正式对公众服务&#xff0c;并且开始收费。现在2024年2月14日就宣布了Gemini 1.5 Pro&#xff0c;史诗级多模态最强MoE首破100万极限上下文纪录&#xff01;&#xff01;&#xff01;Gem…

数据分析 — Pandas 数据加载、存储和清洗

目录 一、文件读取1、常见文件读取函数2、read_csv()3、read_table()4、read_excel()5、read_json()6、read_html()7、大文件读取 二、数据保存1、csv2、excel3、json4、html5、MySQL1、连接数据库2、MySQL 存储到本地3、本地存储到 MySQL 三、数据清洗1、处理缺失值1、判断数据…

Aster实现一台电脑当两台使——副屏使用独立win账号

前言&#xff1a;笔者每年回家&#xff0c;都面临着想要和小伙伴一起玩游戏&#xff0c;但小伙伴没有电脑/只有低配电脑的问题。与此同时&#xff0c;笔者自身的电脑是高配置的电脑&#xff0c;因此笔者想到&#xff0c;能否在自己的电脑上运行游戏&#xff0c;在小伙伴的电脑上…

LaTeX中的documentclass命令:指定文档的类型和整体布局

诸神缄默不语-个人CSDN博文目录 documentclass 是 LaTeX 中一个基础且重要的命令&#xff0c;用于定义文档的整体布局和样式。这个命令告诉 LaTeX 编译器文档是属于哪一类的&#xff0c;比如是文章、报告、书籍等&#xff0c;每一类都有其预定义的格式和结构。 文章目录 基本语…

怎么恢复电脑重装前的数据?介绍几种有效的方法

在日常生活和工作中&#xff0c;电脑已成为我们不可或缺的工具。然而&#xff0c;有时候我们会遇到一些突发情况&#xff0c;比如电脑系统崩溃需要重新安装系统。在这个过程中&#xff0c;我们可能会失去一些重要的数据&#xff0c;比如照片、文档、视频等。这些数据可能包含着…

基于springboot车辆充电桩管理系统源码和论文

随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;车辆充电桩管理系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#xff0c;…

马斯克评 OpenAI 视频模型,接地气又一针见血

马斯克评 OpenAI Sora 昨天&#xff0c;OpenAI 发布了首个视频生成模型 Sora。 一位 X&#xff08;前推特&#xff09;用户分享了 Sora 官网所展示的生成视频&#xff1a;一名女子在东京街头漫步。 该用户评论称&#xff1a;"OpenAI 今天宣布了 Sora&#xff0c;它使用混合…

为什么MySQL不建议使用TEXT字段?

当我们深入探讨“为什么MySQL不建议使用TEXT字段&#xff1f;”这一问题时&#xff0c;可以从一下多个方面来详细理解这个问题&#xff1a; 1. 性能问题 性能问题是MySQL不建议使用TEXT字段的一个重要原因。TEXT字段通常以外部存储方式保存&#xff0c;而不是像固定长度或可变…

C# winfrom实例:四路激光测距雷达数据采集和波形图绘制

1.所述产品 产品型号&#xff1a;TFmini Plus 相关资料下载地址&#xff1a;http://www.benewake.com/download 产品名称&#xff1a;TFmini Plus激光雷达模组制造商公司&#xff1a;北醒&#xff08;北京&#xff09;光子科技有限公司 2.产品功能&#xff1a;TFmini Plus是基…

实现低功耗设计的嵌入式系统技术

&#xff08;本文为简单介绍&#xff0c;观点来源网络&#xff09; 在嵌入式系统设计中&#xff0c;追求低功耗已成为一个核心指标&#xff0c;旨在延长设备的运行时间并提升能效。实现这一目标的途径是多元的&#xff0c;涉及从硬件选型到软件算法的各个层面。 首先&#xf…

【Py/Java/C++三种语言详解】LeetCode每日一题240217【二叉树BFS】LeetCode429、N叉树的层序遍历

有LeetCode交流群/华为OD考试扣扣交流群可加 948025485 可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1336了解算法冲刺训练 文章目录 题目链接题目链接题目描述解题思路DFS和BFS异同用队列维护的BFS 代码PythonJavaC时空复杂度 相关习题华为OD算法/大厂面…

基于MapVGL的地理信息三维度数据增长可视化

写在前面 工作中接触&#xff0c;简单整理博文内容为 基于MapVGL的地理信息维度数据增长可视化 Demo理解不足小伙伴帮忙指正 对每个人而言&#xff0c;真正的职责只有一个&#xff1a;找到自我。然后在心中坚守其一生&#xff0c;全心全意&#xff0c;永不停息。所有其它的路都…

市场复盘总结 20240208

仅用于记录当天的市场情况&#xff0c;用于统计交易策略的适用情况&#xff0c;以便程序回测 短线核心&#xff1a;不参与任何级别的调整&#xff0c;采用龙空龙模式 一支股票 10%的时候可以操作&#xff0c; 90%的时间适合空仓等待 二进三&#xff1a; 进级率中 25% 最常用的…

LGAMEFI基于BPL公链开发的第一生态:开启RWA游戏娱乐与DeFi融合的新纪元

在去中心化金融&#xff08;DeFi&#xff09;与游戏娱乐的结合趋势中&#xff0c;BPL公链上的LGAMEFI项目代表了前沿的技术革新和市场领导。这种将web2上成熟页游进行RWA链改&#xff0c;不仅仅是将游戏热门领域融合&#xff0c;更是在寻找一种全新的参与者经验&#xff0c;将玩…

第五节笔记:LMDeploy 大模型量化部署实践

大模型部署背景 参数用FP16半精度也就是2字节&#xff0c;7B的模型就大约占14G 2.LMDeploy简介 量化降低显存需求量&#xff0c;提高推理速度 大语言模型推理是典型的访问密集型&#xff0c;因为是decoder only的架构&#xff0c;需要token by token的生成&#xff0c;因…

从代码的层面掌握LLM的路线

原则&#xff1a;从易到难&#xff0c;只用 pytorch 从第一个项目来熟悉 transformer 的使用&#xff1b; 从第二个项目来掌握对训练数据的使用方法及 transformer 的 decoder 的细节&#xff1b; 从第三个项目来理解 LLM 的整个过程&#xff1b; 1&#xff0c;Transformer t…

C++-手把手教你模拟实现string

1.string的成员变量 模拟实现string只需要三个成员变量&#xff0c;capacity&#xff0c;size&#xff0c;_str&#xff0c;也就是容量&#xff0c;数据大小&#xff0c;指向字符串的指针。 2.string的构造函数 2.1 使用字符串构造 使用字符串来构造一个string类的对象&…

Days 33 ElfBoard 固定CPU频率

ELF 1开发板选用的是主频800MHz NXP的i.MX6ULL处理器。根据实际的应用场景&#xff0c;如果需要降低CPU功耗&#xff0c;其中一种方法可以将CPU频率固定为节能模式&#xff0c;下面以这款开发板为例给小伙伴们介绍一下固定CPU频率的方法。 先来介绍一下与CPU频率相关的命令&…

希捷与索尼集团合作生产HAMR写头激光二极管

最近有报道指出&#xff0c;希捷&#xff08;Seagate&#xff09;在生产其采用热辅助磁记录&#xff08;HAMR&#xff09;技术的大容量硬盘时&#xff0c;并非所有组件都在内部制造。根据日经新闻的一份新报告&#xff0c;希捷已与索尼集团合作&#xff0c;由索尼为其HAMR写头生…