前端开发需要了解的算法知识

手写深拷贝

function deepClone(obj) {
    // 处理基础数据类型和函数
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    // 处理数组
    if (Array.isArray(obj)) {
        return obj.map(item => deepClone(item));
    }
    // 处理对象
    const clonedObj = {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clonedObj[key] = deepClone(obj[key]);
        }
    }
    return clonedObj;
}

const original = {
    a: 1,
    b: [2, 3],
    c: { d: 4 }
};
const copy = deepClone(original);
console.log(copy);

冒泡排序

对于一组要排序的元素列,依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面,如此继续,直到比较到最后的两个数,将小数放在前面,大数放在后面,重复步骤,直至全部排序完成

function bubbleSort(arr) {
    let n = arr.length;
    for (let i = 0; i < n - 1; i++) {
        for (let j = 0; j < n - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                // 交换
                [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
            }
        }
    }
    return arr;
}

const array = [64, 34, 25, 12, 22, 11, 90];
console.log(bubbleSort(array)); // 输出: [11, 12, 22, 25, 34, 64, 90]

快速排序

快速排序是对冒泡排序的一种改进,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按照此方法对这两部分数据分别进行快速排序

function quickSort(arr) {
    if (arr.length <= 1) {
        return arr; // 基本情况:数组为空或只有一个元素时,直接返回
    }
    const pivot = arr[arr.length - 1]; // 选择最后一个元素作为基准
    const left = []; // 存放小于基准的元素
    const right = []; // 存放大于基准的元素
    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]); // 小于基准的元素放左边
        } else {
            right.push(arr[i]); // 大于基准的元素放右边
        }
    }
    // 递归排序左边和右边,并结合基准
    return [...quickSort(left), pivot, ...quickSort(right)];
}

const array = [3, 6, 8, 10, 1, 2, 1];
const sortedArray = quickSort(array);
console.log(sortedArray); // [1, 1, 2, 3, 6, 8, 10]

深度平铺数组

function flattenArray(arr) {
    return arr.reduce((acc, val) => {
        return Array.isArray(val) 
            ? acc.concat(flattenArray(val)) // 递归调用
            : acc.concat(val); // 直接添加元素
    }, []);
}

const nestedArray = [1, [2, [3, 4], 5], 6, [7, 8]];
const flatArray = flattenArray(nestedArray);
console.log(flatArray); // [1, 2, 3, 4, 5, 6, 7, 8]

数组去重

方法一:

const uniqueArray = arr => [...new Set(arr)];

const arr = [1, 2, 2, 3, 4, 4, 5];
const result = uniqueArray(arr);
console.log(result); // [1, 2, 3, 4, 5]

方法二:

const uniqueArray = arr => arr.filter((value, index) => arr.indexOf(value) === index);

const arr = [1, 2, 2, 3, 4, 4, 5];
const result = uniqueArray(arr);
console.log(result); // [1, 2, 3, 4, 5]

方法三:

const uniqueArray = arr => arr.reduce((acc, value) => {
    if (!acc.includes(value)) {
        acc.push(value);
    }
    return acc;
}, []);

const arr = [1, 2, 2, 3, 4, 4, 5];
const result = uniqueArray(arr);
console.log(result); // [1, 2, 3, 4, 5]

将数字转化为千分位格式

方法一:

const formatNumber = num => num.toLocaleString();

const num = 1234567.89;
const result = formatNumber(num);
console.log(result); // "1,234,567.89"

方法二:

const formatNumber = num => {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};

const num = 1234567.89;
const result = formatNumber(num);
console.log(result); // "1,234,567.89"

计算函数执行所花费的时间

方法一:

function exampleFunction() {
    // 模拟一些耗时操作
    for (let i = 0; i < 1e6; i++) {}
}

console.time('Function Execution Time');
exampleFunction();
console.timeEnd('Function Execution Time'); // 输出函数执行所花费的时间

方法二:

function exampleFunction() {
    // 模拟一些耗时操作
    for (let i = 0; i < 1e6; i++) {}
}

const start = performance.now();
exampleFunction();
const end = performance.now();
console.log(`Function Execution Time: ${end - start} milliseconds`);

解析url参数

方法一:

const url = 'https://example.com/?name=John&age=30';
const params = new URL(url).searchParams;
const name = params.get('name'); // 'John'
const age = params.get('age'); // '30'
console.log(name, age);

方法二:

function getQueryParams(url) {
    const queryString = url.split('?')[1];
    if (!queryString) return {};
    return queryString.split('&').reduce((params, param) => {
        const [key, value] = param.split('=');
        params[decodeURIComponent(key)] = decodeURIComponent(value || '');
        return params;
    }, {});
}

const url = 'https://example.com/?name=John&age=30';
const params = getQueryParams(url);
console.log(params); // { name: 'John', age: '30' }

方法三:

使用 qs 这个库

const qs = require('qs');
const url = 'https://example.com/?name=John&age=30';
const queryString = url.split('?')[1]; // 获取查询字符串部分
const params = qs.parse(queryString);
console.log(params); // { name: 'John', age: '30' }

合并对象

方法一:

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = Object.assign({}, obj1, obj2);
console.log(merged); // { a: 1, b: 3, c: 4 }

方法二:

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 3, c: 4 }

方法三:

const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = [obj1, obj2].reduce((acc, obj) => {
  Object.entries(obj).forEach(([key, value]) => {
    acc[key] = value;
  });
  return acc;
}, {});
console.log(merged); // { a: 1, b: 3, c: 4 }

对象转换为键值对

方法一:

const obj = { a: 1, b: 2, c: 3 };
const entries = Object.entries(obj);
console.log(entries); // [['a', 1], ['b', 2], ['c', 3]]

方法二:

const obj = { a: 1, b: 2, c: 3 };
const entries = Object.keys(obj).map(key => [key, obj[key]]);
console.log(entries); // [['a', 1], ['b', 2], ['c', 3]]

方法三:

使用 for...in 循环

const obj = { a: 1, b: 2, c: 3 };
const entries = [];
for (const key in obj) {
    entries.push([key, obj[key]]);
}
console.log(entries); // [['a', 1], ['b', 2], ['c', 3]]

散列算法

散列算法(Hashing)是一种将输入数据(通常是任意大小)转换成固定大小的输出(散列值或哈希值)的算法。它广泛应用于数据结构(如哈希表)、数据完整性验证、数字签名等

特点:

  • 固定长度输出;无论输入数据多大,输出都是固定长度
  • 快速计算;对输入数据进行哈希计算的速度很快
  • 抗碰撞;不同的输入应进行产生不同的输出
  • 不可逆;从哈希值不能反推原始输入

方法一:

简单的 SHA-256 散列算法实现,使用 `crypto` 模块(Node.js 环境)

const crypto = require('crypto');
function hashData(data) {
    return crypto.createHash('sha256').update(data).digest('hex');
}

const data = 'Hello, world!';
const hashValue = hashData(data);
console.log(hashValue); // 输出哈希值

方法二:

使用 Web Crypto API(浏览器环境)

async function hashData(data) {
    const encoder = new TextEncoder();
    const dataBuffer = encoder.encode(data);
    const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

hashData('Hello, world!').then(hashValue => {
    console.log(hashValue); // 输出哈希值
});

幂集

幂集是一个集合的所有子集的集合,包括空集和自身

通过递归来计算

function powerSet(arr) {
    const result = [];
    function generate(subset, index) {
        if (index === arr.length) {
            result.push(subset);
            return;
        }
        generate(subset, index + 1); // 不包含当前元素
        generate([...subset, arr[index]], index + 1); // 包含当前元素
    }
    generate([], 0);
    return result;
}

const set = [1, 2, 3];
const pSet = powerSet(set);
console.log(pSet);
// 输出[ [], [ 1 ], [ 2 ], [ 1, 2 ], [ 3 ], [ 1, 3 ], [ 2, 3 ], [ 1, 2, 3 ] ]

最大公约数

最大公约数是能整除两个或多个整数的最大正整数

使用欧几里得算法来计算最大公约数

function gcd(a, b) {
    while (b !== 0) {
        const temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

const num1 = 48;
const num2 = 18;
const result = gcd(num1, num2);
console.log(result); // 输出 6

生成斐波那契数组

斐波那契数组是由斐波那契数列生成的数组,数列中的每个数都是前两个数的和,通常以 `0` 和 `1` 开始。数列的前几个数是:`0, 1, 1, 2, 3, 5, 8, 13, ...`

function generateFibonacci(n) {
    const fib = [0, 1];
    for (let i = 2; i < n; i++) {
        fib[i] = fib[i - 1] + fib[i - 2];
    }
    return fib.slice(0, n);
}

const num = 10;
const fibonacciArray = generateFibonacci(num);
console.log(fibonacciArray); // 输出 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

你可能感兴趣的:(算法,前端)