JavaScript中的常见算法

news2024/11/28 0:29:21

一.排序算法

1.冒泡排序


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

function bubbleSort(arr) {
    const { length } = arr
    for (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 } = arr
    let min
    for (let i = 0; i < length - 1; i++) {
        min = i
        for (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 } = arr
    let temp
    for (let i = 1; i < length; i++) {
        temp = arr[i]
        let j = i
        while (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 = 0
    counts.forEach((item, index) => {
        while (item > 0) {
            newArr[sortIndex++] = index
            item--
        }
    })
    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) + 1
    const 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 } = arr
    let temp
    for (let i = 1; i < length; i++) {
        temp = arr[i]
        let j = i
        while (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 = 10
    let divider = 1
    let 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 || 0
    end = end || arr.length - 1
    arr = 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 } = 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))
}

3.内插搜索 

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

//适合数值分布比较均匀的数组
function insertSearch(find, arr, start, end) {
    start = start || 0
    end = end || arr.length - 1
    arr = 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 } = 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))
}

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

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

function shuffleArray(array) {
  let n = array.length
  let random
  while (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 - 1
    let 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.length
    var n = str2.length
    var dp = [new Array(n + 1).fill(0)] //第一行全是0
    console.log(dp);
    for (var i = 1; i <= m; i++) { //一共有m+1行
        dp[i] = [0] //第一列全是0
        for (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 = 0
    for (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.value
            capacity = capacity - item.weight
        } else if (item.capacity > capacity && capacity > 0) {
            let rate = capacity / item.weight
            select.push({
                num: item.num,
                weight: item.weight * rate,
                value: item.value * rate,
                rate
            })
            total = total + item.value * rate
            break
        } 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.coloradmin.cn/o/1448510.html

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

相关文章

C语言—数组一维(含冒泡排序)

1.用数组存储10个整型数&#xff0c;通过键盘输入一个数&#xff0c;找出该数在数组中的下标值&#xff1b; /*1.用数组存储10个整型数&#xff0c;通过键盘输入一个数&#xff0c;找出该数在数组中的下标值&#xff1b;*/#include <stdio.h>int main(void) {int nums[…

静态时序分析:SDC约束命令set_clock_uncertainty

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 set_clock_uncertainty是用来指定设计中时钟周期的不确定性&#xff0c;不确定性指的是对那些会对时钟周期造成的负面影响。这些不确定性可能来源于时钟抖动(clo…

mysql8.0.36主从复制(读写分离)配置教程

1、关闭防火墙 使用命令行关闭防火墙 在Ubuntu系统中&#xff0c;可以使用以下命令关闭防火墙&#xff1a; sudo ufw disable执行该命令后&#xff0c;系统会提示是否要关闭防火墙&#xff0c;确认后即可关闭防火墙。 查看防火墙状态 使用以下命令可以查看防火墙当前的状…

代码随想录Day50 | 70. 爬楼梯 322. 零钱兑换 279.完全平方数

代码随想录Day50 | 70. 爬楼梯 322. 零钱兑换 279.完全平方数 70.爬楼梯322.零钱兑换279.完全平方数 70.爬楼梯 文档讲解&#xff1a;代码随想录 视频讲解&#xff1a; 状态 dp数组 dp[j]表示爬上第j阶台阶需要的方法数递推公式&#xff0c;由于在每一阶台阶可以向上走1~m阶&a…

AGV|RGV基本概念及导航分类与差异

AGV是自动导引运输车&#xff0c;装备采用电磁或光学等自动导引装置&#xff0c;能够沿规定的导引路径行驶&#xff0c;具有安全保护以及各种移载功能的运输车。其导航方式主要分磁条|磁钉导航、激光导航、激光反光板、激光自然导航、二维码导航、惯性导航等方式&#xff0c;广…

Java学习手册——第七篇基础语法

Java学习手册——第七篇基础语法 1. 注释2. 顺序语句3. 条件语句3.1 if语句3.2 switch语句 4. 循环语句4.1 for循环4.2 while 语句4.3 do...while语句 本篇为大家快速入门Java基础语法&#xff0c;了解一个语言的基础语法是必要的&#xff0c; 因为我们后期都是需要用这些基础语…

Kafka(三)(集成SpringBoot)

第三章 Kafka集成 SpringBoot SpringBoot 是一个在 JavaEE 开发中非常常用的组件。可以用于 Kafka 的生产者&#xff0c;也可以 用于 SpringBoot 的消费者。 在初始化springboot环境的时候要勾选kafka依赖 <dependency><groupId>org.springframework.kafka</gr…

【基础】第K大与第K小数

说明 给定一个长度为N(0< n< 10000)的序列&#xff0c;保证每一个序列中的数字a[i]是正整数 &#xff0c;编程要求求出整个序列中第k大的数字减去第k小的数字的值m&#xff0c;并判断m是否为质数。(0< k< n) 输入数据 第一行为2个数n&#xff0c;k&#xff08;…

步步深入 k8s 使用 pv pvc sc 在 nfs 基础上共享存储

博客原文 文章目录 前言集群环境nfs 环境搭建pod 挂载 nfs架构图 pvc 方式挂载 nfs架构图 storageclass 方式动态申请 pv架构图 参考 前言 持久化卷&#xff08;Persistent Volume, PV&#xff09;允许用户将外部存储映射到集群&#xff0c;而持久化卷申请&#xff08;Persist…

[Java][算法 滑动窗口]Day 02---LeetCode 热题 100---08~09

第一题 无重复字符串的最长子串 思路 其实就是在字符串S中 找到没有重复的最长子串的长度 这道题的难点就是在于如何判断最长并且无重复 首先 最长长度 可以使用变量max记录保存 再者 判断有无重复 最简单的方法就是 暴力遍历法 即对于每次找的子串都再次寻找遍历…

【Django】Django内建用户系统

Django内建用户系统 14.1 Django中的用户认证 Django带有一个用户认证系统系统&#xff0c;它处理用户用户账号、组、权限以及基于cookie的用户会话。 用户可以直接使用Django自带的用户表。 官方文档&#xff1a;https://docs.djangoproject.com/zh-hans/2.2/topics/auth/ …

计算机组成原理 2 数据表示

机器数 研究机器内的数据表示&#xff0c;目的在于组织数据&#xff0c;方便计算机硬件直接使用。 需要考虑&#xff1a; 支持的数据类型&#xff1b; 能表示的数据精度&#xff1b; 是否有利于软件的移植 能表示的数据范围&#xff1b; 存储和处理的代价&#xff1b; ... 真值…

ELAdmin 配置定时任务

定义方法 在自己的 Module 中写个要执行的方法。 比如获取微信公众号的 accessToken&#xff0c;每两个小时更新一次。这种的其实使用 Spring 的 Scheduled 更方便些&#xff0c;此处仅为演示。 package me.zhengjie.mp.task;import com.alibaba.fastjson.JSON; import lombo…

基于Linux的nfs、samba网络服务搭建

我学的Ubuntu&#xff0c;以它为例子 一、nfs(linux <---> linux) 1.1.nfs首先搭建服务端&#xff08;对外共享&#xff09; //安装nfs核心服务 sudo apt update sudo apt install nfs-kernel-server //配置nfs文件(指定共享文件) sudo vim /etc/exports //重启nf…

H5 渐变3D旋转个人主页引导页源码

H5 渐变3D旋转个人主页引导页源码 源码介绍&#xff1a;一款渐变3D旋转个人主页引导页源码&#xff0c;可以做个人主页/旗下网站引导 下载地址&#xff1a; https://www.changyouzuhao.cn/10392.html

第三百四十五回

文章目录 1. 概念介绍2. 方法与功能2.1 基本用法2.2 加密算法 3. 示例代码4. 内容总结 我们在上一章回中介绍了"FlutterCacheManager组件"相关的内容&#xff0c;本章回中将介绍一个加密工具包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 加密主要…

【MySQL进阶之路】通过实操理解 explain 执行计划

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

【刷题记录】——2024寒假day9编程题

本系列博客为个人刷题思路分享&#xff0c;有需要借鉴即可。 1.目录大纲&#xff1a; 2.题目链接&#xff1a; T1:LINK T2:LINK 3.详解思路&#xff1a; T1: 思路&#xff1a; /*** Note: The returned array must be malloced, assume caller calls free().*/#include<…

计算机网络——11EMail

EMail 电子邮件&#xff08;EMail&#xff09; 3个主要组成部分 用户代理邮件服务器简单邮件传输协议&#xff1a;SMTP 用户代理 又名“邮件阅读器”撰写、编辑和阅读邮件输入和输出邮件保存在服务器上 邮件服务器 邮箱中管理和维护发送给用户的邮件输出报文队列保持待发…

【成长记录】第一次写博客入csdn榜单了 还是第一.....

庆祝一下第一次拿综合榜榜一 Java内容榜第二 总之谢谢大家支持 小苏会继续努力的 可以看看我的新作 嘻嘻&#x1f601;&#x1f924;&#x1f449;&#x1f3fb;&#x1f448;&#x1f3fb; 谢谢大家