FPF   付鹏篚的笔记
  • 主页
  • 归档
  • 分类
  • 标签
  • 关于

付鹏篚

  • 主页
  • 归档
  • 分类
  • 标签
  • 关于
Quiet主题
  • JavaScript

JavaScript简单算法

付鹏篚
JavaScript

2018-07-12 20:00:00

文章目录
  1. 1. 冒泡排序(Bubble Sort)
  2. 2. 选择排序(Selection Sort)
  3. 3. 插入排序(Insertion Sort)
  4. 4. 快速排序(Quick Sort)
  5. 5. 二分查找(Binary Search)
  6. 6. 斐波那契数列(Fibonacci Sequence)
    1. 递归实现:
    2. 动态规划实现:
  7. 7. 反转字符串(Reverse String)
    1. 使用 split、reverse 和 join:
    2. 使用循环:
  8. 8. 判断回文(Palindrome)
  9. 9. 求最大公约数(GCD)
  10. 10. 深拷贝(Deep Clone)
  11. 11. 计数排序(Counting Sort)
  12. 12. 异或交换两个数
  13. 13. 合并两个有序数组

好的,下面是更详细的 JavaScript 经典算法实现,包含了更多的算法示例,并对每个代码进行了注释,帮助理解每一步的实现过程。

1. 冒泡排序(Bubble Sort)

冒泡排序是一种通过反复遍历待排序数组,比较相邻的元素并交换它们,直到数组有序的排序方法。

function bubbleSort(arr) {
  let n = arr.length;
  for (let i = 0; i < n; i++) {
    // 每次遍历,从0到n-i-1,i是已经排序好的元素个数
    for (let j = 0; j < n - i - 1; j++) {
      // 如果相邻元素逆序,则交换它们
      if (arr[j] > arr[j + 1]) {
        [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
      }
    }
  }
  return arr;
}

2. 选择排序(Selection Sort)

选择排序通过不断选择未排序部分中的最小(或最大)元素,将其与未排序部分的第一个元素交换。

function selectionSort(arr) {
  let n = arr.length;
  for (let i = 0; i < n; i++) {
    let minIndex = i;
    for (let j = i + 1; j < n; j++) {
      // 找到未排序部分中的最小元素
      if (arr[j] < arr[minIndex]) {
        minIndex = j;
      }
    }
    // 交换当前元素和最小元素
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
  }
  return arr;
}

3. 插入排序(Insertion Sort)

插入排序通过将每个元素插入到已排序部分的正确位置来完成排序。

function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    let current = arr[i];
    let j = i - 1;
    // 将当前元素插入到前面的已排序部分
    while (j >= 0 && arr[j] > current) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = current;
  }
  return arr;
}

4. 快速排序(Quick Sort)

快速排序通过选择一个基准元素,将数组分成两部分,其中一部分的所有元素都比基准小,另一部分都比基准大,然后递归排序这两部分。

function quickSort(arr) {
  if (arr.length <= 1) return arr;  // 如果数组长度小于等于1,直接返回数组

  const pivot = arr[arr.length - 1];  // 选择数组最后一个元素作为基准
  let left = [], 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)];
}

5. 二分查找(Binary Search)

二分查找是一种高效的查找方法,前提是数组必须已经排好序。通过每次将查找范围折半来缩小查找范围。

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;  // 找到目标元素
    }
    if (arr[mid] < target) {
      left = mid + 1;  // 目标在右半部分
    } else {
      right = mid - 1;  // 目标在左半部分
    }
  }
  return -1;  // 没有找到目标元素
}

6. 斐波那契数列(Fibonacci Sequence)

斐波那契数列是一个经典的递归问题,数列中的每个数字都是前两个数字之和。可以通过递归、动态规划和迭代等方法求解。

递归实现:

function fibonacci(n) {
  if (n <= 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);  // 递归调用
}

动态规划实现:

function fibonacciDP(n) {
  if (n <= 1) return n;
  let fib = [0, 1];
  for (let i = 2; i <= n; i++) {
    fib[i] = fib[i - 1] + fib[i - 2];  // 每次计算当前元素
  }
  return fib[n];
}

7. 反转字符串(Reverse String)

通过不同的方法反转一个字符串。

使用 split、reverse 和 join:

function reverseString(str) {
  return str.split('').reverse().join('');  // 拆分字符串,反转,合并
}

使用循环:

function reverseString(str) {
  let result = '';
  for (let i = str.length - 1; i >= 0; i--) {
    result += str[i];  // 从后往前遍历字符并拼接
  }
  return result;
}

8. 判断回文(Palindrome)

回文是指正着读和反着读都一样的字符串。判断一个字符串是否是回文可以通过比对字符串的两端来实现。

function isPalindrome(str) {
  const reversedStr = str.split('').reverse().join('');
  return str === reversedStr;  // 比较原字符串和反转后的字符串
}

9. 求最大公约数(GCD)

最大公约数是能同时整除两个数的最大整数。可以使用欧几里得算法来求解。

function gcd(a, b) {
  while (b !== 0) {
    let temp = b;
    b = a % b;  // 求余数
    a = temp;   // 更新a和b
  }
  return a;  // 返回最大公约数
}

10. 深拷贝(Deep Clone)

深拷贝是创建一个新的对象,新的对象完全复制原对象的结构和数据。

function deepClone(obj) {
  if (typeof obj !== 'object' || obj === null) return obj;  // 不是对象直接返回

  let copy;
  if (Array.isArray(obj)) {
    copy = [];
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepClone(obj[i]);  // 递归处理数组中的元素
    }
  } else {
    copy = {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepClone(obj[key]);  // 递归处理对象中的属性
      }
    }
  }

  return copy;
}

11. 计数排序(Counting Sort)

计数排序是一个基于元素计数的排序算法,适用于范围有限的整数排序。

function countingSort(arr) {
  let max = Math.max(...arr);  // 找到数组中的最大值
  let count = new Array(max + 1).fill(0);  // 创建计数数组

  arr.forEach(num => count[num]++);  // 统计每个元素出现的次数
  
  let result = [];
  for (let i = 0; i < count.length; i++) {
    while (count[i] > 0) {
      result.push(i);
      count[i]--;
    }
  }

  return result;
}

12. 异或交换两个数

通过异或操作交换两个数的值,不需要临时变量。

function swap(a, b) {
  a ^= b;
  b ^= a;
  a ^= b;  // 通过异或交换值
  return [a, b];
}

13. 合并两个有序数组

将两个有序数组合并成一个新的有序数组。

function mergeSortedArrays(arr1, arr2) {
  let result = [];
  let i = 0, j = 0;
  
  // 合并过程
  while (i < arr1.length && j < arr2.length) {
    if (arr1[i] < arr2[j]) {
      result.push(arr1[i]);
      i++;
    } else {
      result.push(arr2[j]);
      j++;
    }
  }

  // 处理剩余部分
  return result.concat(arr1.slice(i), arr2.slice(j));
}
### 总结

这些经典的 JavaScript 算法涵盖了排序、查找、递归、字符串处理、数学问题等基本问题。掌握这些算法的实现有助于提升编程能力,并且能帮助你更好地理解数据结构和算法的设计思想。
上一篇

Hexo博客配置与使用指南

©2025 By 付鹏篚. 主题:Quiet
Quiet主题