【JS】常用排序、搜索、数组与字符串处理算法

一、排序算法

1.冒泡排序

基本思想:重复地走访要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

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

2.快速排序

基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

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)];
}

3.选择排序

基本思想:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

function selectionSort(arr) {
    const n = arr.length;
    for (let i = 0; i < n - 1; i++) {
        let minIndex = i;
        for (let j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        if (minIndex!== i) {
            // 交换元素
            const temp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = temp;
        }
    }
    return arr;
}

二、搜索算法

1. 线性搜索

基本思想:从数组的一端开始,逐个检查每个元素,直到找到目标元素或遍历完整个数组。

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

2. 二分搜索

基本思想:针对一个有序数组,每次取中间值与目标值比较,根据比较结果缩小搜索范围,重复这个过程直到找到目标值或确定目标值不存在。

function binarySearch(arr, target) {
  let left = 0;
  let right = arr.length - 1;
  while (left <= right) {
    const mid = Math.floor((left + right) / 2);
    if (arr[mid] === target) {
      return mid;
    } else if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid - 1;
    }
  }
  return -1;
}

三、数组和字符串相关算法

1. 数组去重

方法一:使用 ES6 的 Set 和扩展运算符

function removeDuplicates(arr) {
  return [...new Set(arr)];
}

方法二:遍历数组并使用对象存储已出现的元素

const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArray = [];
const seen = {};
for (const item of arr) {
  if (!seen[item]) {
    uniqueArray.push(item);
    seen[item] = true;
  }
}
console.log(uniqueArray); // [1, 2, 3, 4, 5]

2. 查找数组中的最大值和最小值

方法一:循环遍历

const arr = [5, 3, 8, 4, 2];
let min = arr[0];
let max = arr[0];
for (const item of arr) {
  if (item < min) {
    min = item;
  }
  if (item > max) {
    max = item;
  }
}
console.log(`最小值:${min},最大值:${max}`); // 最小值:2,最大值:8

方法二:使用Math.min()和Math.max()结合扩展运算符

const arr = [5, 3, 8, 4, 2];
const minValue = Math.min(...arr);
const maxValue = Math.max(...arr);
console.log(`最小值:${minValue},最大值:${maxValue}`); // 最小值:2,最大值:8

3. 字符串反转

方法一:使用循环遍历和拼接。

function reverseString(str) {
  let reversed = '';
  for (let i = str.length - 1; i >= 0; i--) {
    reversed += str[i];
  }
  return reversed;
}

方法二:使用数组的reverse()方法和join()方法

const str = "hello";
const reversedStr = str.split("").reverse().join("");
console.log(reversedStr); // "olleh"

4. 判断一个字符串是否为回文字符串

方法一:使用循环遍历比较字符

const str = "racecar";
let isPalindrome = true;
for (let i = 0; i < str.length / 2; i++) {
  if (str[i]!== str[str.length - 1 - i]) {
    isPalindrome = false;
    break;
  }
}
console.log(isPalindrome); // true

方法二:使用字符串反转后比较

const str = "racecar";
const reversedStr = str.split("").reverse().join("");
const isPalindrome = str === reversedStr;
console.log(isPalindrome); // true

5. 数组转字符串

方法一:使用join()方法

join()方法将数组的所有元素连接成一个字符串,并可以指定连接的分隔符。如果不指定分隔符,默认使用逗号,连接。

const arr = ['apple', 'banana', 'cherry'];
const str = arr.join();
console.log(str); // "apple,banana,cherry"

const strWithSeparator = arr.join('-');
console.log(strWithSeparator); // "apple-banana-cherry"

方法二:使用toString()方法

toString()方法也可以将数组转换为字符串,它的效果和使用默认分隔符的join()方法类似。

const arr = [1, 2, 3];
const str = arr.toString();
console.log(str); // "1,2,3"

6. 字符串转数组

方法一:使用split()方法

split()方法可以将字符串分割成数组,根据指定的分隔符进行分割。如果不指定分隔符,将字符串分割成单个字符的数组。

const str = "apple,banana,cherry";
const arr = str.split(',');
console.log(arr); // ["apple", "banana", "cherry"]

const str2 = "hello";
const arr2 = str2.split('');
console.log(arr2); // ["h", "e", "l", "l", "o"]

方法二:使用扩展运算符[…string]

ES6 的扩展运算符可以将字符串转换为字符数组。

const str = "world";
const arr = [...str];
console.log(arr); // ["w", "o", "r", "l", "d"]

7. 数组扁平化

将一个多维数组转变为一个一维数组

const arr = [1, [2, [3, [4, 5]]], 6];
// => [1, 2, 3, 4, 5, 6]

方法一: 使用es6新方法flat()

depth指定要提取嵌套数组的结构深度,默认值为1.

const res1 = arr.flat(depth);

方法二:利用正则

转成字符串再替换中括号再转成数组,但数据类型都会变为字符串。

const res2 = JSON.stringify(arr).replace(/[|]/g, '').split(',');

方法三:JSON方法加正则

转成字符串再替换中括号再转成数组,全程使用JSON,保证了数据格式不变。

const res3 = JSON.parse('[' + JSON.stringify(arr).replace(/[|]/g, '') + ']');

方法四:使用reduce和concat

const flatten = arr => {
  return arr.reduce((pre, cur) => {
    return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);
  }, [])
}
const res4 = flatten(arr);

方法五:函数递归

const res5 = [];
const fn = arr => {
  for (let i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i])) {
      fn(arr[i]);
    } else {
      res5.push(arr[i]);
    }
  }
}
fn(arr);

8. 数组交集

由所有属于集合A且属于集合B的元素所组成的集合,叫做集合A与集合B的交集

利用循环和indexOf、include

  • 利用indexOf
const intersection1 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (arr2.indexOf(arr1[i]) !== -1) res.push(arr1[i]);
  }
  return res;
};
  • 利用include
const intersection2 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (arr2.includes(arr1[i])) res.push(arr1[i]);
  }
  return res;
};

9. 数组差集

差集:A和B是两个集合,则所有属于A且不属于B的元素构成的集合,叫做集合A和集合B的差集。

利用循环和indexOf、include

  • 利用indexOf
const intersection1 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (arr2.indexOf(arr1[i]) == -1) res.push(arr1[i]);
  }
  return res;
};
  • 利用include
const intersection2 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (!arr2.includes(arr1[i])) res.push(arr1[i]);
  }
  return res;
};

10. 数组并集

给定两个集合A,B,把它们所有的元素合并在一起组成的集合,叫做集合A与集合B的并集

方法一:利用concat并结合Set

先将两个数组连成一个数组,然后去重

const res1 = Array.from(new Set(arr1.concat(arr2)));

方法二:利用循环和indexOf、include

  • 利用indexOf
const union1 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (arr2.indexOf(arr1[i]) == -1) res.push(arr1[i]);
  }
  return arr2.concat(res);
};
  • 利用include
const union2 = (arr1, arr2) => {
  const res = [];
  for (let i = 0; i < arr1.length; i++) {
    if (!arr2.includes(arr1[i])) res.push(arr1[i]);
  }
  return arr2.concat(res);
};

11. 列表转成树结构

例如:

[
  {
    id: 1,
    text: "节点1",
    parentId: 0, //这里用0表示为根节点
  },
  {
    id: 2,
    text: "节点1_1",
    parentId: 1, // 通过这个字段来确定子父级
  },
  // ...
]

// 转成

[
  {
    id: 1,
    text: "节点1",
    parentId: 0,
    children: [
      {
        id: 2,
        text: "节点1_1",
        parentId: 1,
      },
    ],
  }
  // ...
];

实现方法:

function listToTree(data) {
  let temp = {};
  let treeData = [];
  // 放到临时对象,方便获取
  for (let i = 0; i < data.length; i++) {
    temp[data[i].id] = data[i];
  }
  // 遍历
  for (let i in temp) {
    // 不是根节点
    if (+temp[i].parentId != 0) {
      第一次添加就先初始化children数组
      if (!temp[temp[i].parentId].children) {
        temp[temp[i].parentId].children = [];
      }
      temp[temp[i].parentId].children.push(temp[i]);
    } else {
      // 根节点直接放到数组
      treeData.push(temp[i]);
    }
  }
  return treeData;
}

12. 树形结构转成列表

例如:

[
  {
    id: 1,
    text: "节点1",
    parentId: 0,
    children: [
      {
        id: 2,
        text: "节点1_1",
        parentId: 1,
      },
    ],
  },
  // ...
]

// 转成

[
  {
    id: 1,
    text: "节点1",
    parentId: 0, //这里用0表示为根节点
  },
  {
    id: 2,
    text: "节点1_1",
    parentId: 1, //通过这个字段来确定子父级
  }
];

实现方法:

function treeToList(data) {
  let res = [];
  // 定义转换方法
  const tl = (tree) => {
    tree.forEach((item) => {
      if (item.children) {
        // 递归
        tl(item.children);
        delete item.children;
      }
      res.push(item);
    });
  };
  
  tl(data);
  return res;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值