返回

开启算法之门:JavaScript必会排序算法大PK

前端

踏入算法殿堂,解锁排序奥秘

在计算机科学的世界里,算法是程序员的必备工具,而排序算法更是其中不可或缺的重要组成部分。JavaScript作为一门强大的编程语言,提供了丰富的排序算法,每种算法都有其独特的优势和适用场景。

排序算法的类型

排序算法可以分为两大类:比较排序非比较排序

  • 比较排序 :通过比较元素的大小来排序,包括冒泡排序、选择排序、插入排序等。
  • 非比较排序 :不需要比较元素的大小,包括计数排序、桶排序、基数排序等。

常见的排序算法

以下是JavaScript中常见的排序算法:

1. 冒泡排序

冒泡排序是一种最简单的排序算法,它通过不断比较相邻元素,将较大的元素“泡”到数组末尾。算法简单易懂,但效率较低,只适用于小规模数据排序。

function bubbleSort(arr) {
  let swapped;
  do {
    swapped = false;
    for (let i = 1; i < arr.length; i++) {
      if (arr[i - 1] > arr[i]) {
        [arr[i - 1], arr[i]] = [arr[i], arr[i - 1]];
        swapped = true;
      }
    }
  } while (swapped);
  return arr;
}

2. 选择排序

选择排序通过在未排序部分寻找最值元素,并将其与当前位置的元素交换,以此实现排序。算法效率比冒泡排序更高,但仍属于低效算法。

function selectionSort(arr) {
  for (let i = 0; i < arr.length; i++) {
    let minIndex = i;
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j;
      }
    }
    [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
  }
  return arr;
}

3. 快速排序

快速排序是一种分治算法,通过递归的方式将数组划分为更小的子数组,再对子数组进行排序,最后合并子数组得到最终排序结果。算法效率极高,是目前最常用的排序算法之一。

function quickSort(arr) {
  if (arr.length <= 1) return arr;

  const pivot = arr[Math.floor(arr.length / 2)];
  const left = [];
  const right = [];

  for (let i = 0; i < arr.length; i++) {
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else if (arr[i] > pivot) {
      right.push(arr[i]);
    }
  }

  return [...quickSort(left), pivot, ...quickSort(right)];
}

4. 插入排序

插入排序是一种直观且高效的排序算法,通过将元素插入到已排序的子数组中,依次完成排序。算法在处理已排序或局部排序的数据时表现出色。

function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    const key = arr[i];
    let j = i - 1;

    while (j >= 0 && arr[j] > key) {
      arr[j + 1] = arr[j];
      j--;
    }

    arr[j + 1] = key;
  }

  return arr;
}

5. 希尔排序

希尔排序是一种改进的插入排序算法,通过设置不同的间隔,将数组划分为更小的子数组,再对子数组进行插入排序,最后合并子数组得到最终排序结果。

function shellSort(arr) {
  const gap = Math.floor(arr.length / 2);

  while (gap > 0) {
    for (let i = gap; i < arr.length; i++) {
      const key = arr[i];
      let j = i - gap;

      while (j >= 0 && arr[j] > key) {
        arr[j + gap] = arr[j];
        j -= gap;
      }

      arr[j + gap] = key;
    }

    gap = Math.floor(gap / 2);
  }

  return arr;
}

6. 归并排序

归并排序也是一种分治算法,通过递归的方式将数组划分为更小的子数组,再对子数组进行排序,最后合并子数组得到最终排序结果。算法效率稳定,是目前最常用的排序算法之一。

function mergeSort(arr) {
  if (arr.length <= 1) return arr;

  const mid = Math.floor(arr.length / 2);
  const left = arr.slice(0, mid);
  const right = arr.slice(mid);

  return merge(mergeSort(left), mergeSort(right));
}

function merge(left, right) {
  const result = [];
  let i = 0;
  let j = 0;

  while (i < left.length && j < right.length) {
    if (left[i] < right[j]) {
      result.push(left[i]);
      i++;
    } else {
      result.push(right[j]);
      j++;
    }
  }

  return [...result, ...left.slice(i), ...right.slice(j)];
}

7. 计数排序

计数排序是一种特殊的排序算法,适用于元素范围有限且分布均匀的数据。算法通过统计元素的出现次数,并根据统计结果确定元素的最终位置,以此实现排序。

function countingSort(arr, max) {
  const count = new Array(max + 1).fill(0);

  for (const num of arr) {
    count[num]++;
  }

  let i = 0;
  for (let j = 0; j <= max; j++) {
    while (count[j] > 0) {
      arr[i] = j;
      i++;
      count[j]--;
    }
  }

  return arr;
}

8. 桶排序

桶排序适用于均匀分布数据的排序算法。算法通过将数组划分为多个桶,并将元素分配到相应的桶中,再对每个桶中的元素进行排序,最后合并各桶的排序结果得到最终排序结果。

function bucketSort(arr, bucketSize) {
  const buckets = [];

  for (let i = 0; i < bucketSize; i++) {
    buckets.push([]);
  }

  for (const num of arr) {
    const bucketIndex = Math.floor(num / bucketSize);
    buckets[bucketIndex].push(num);
  }

  for (const bucket of buckets) {
    bucket.sort((a, b) => a - b);
  }

  return [].concat(...buckets);
}

9. 基数排序

基数排序适用于非负整数的排序算法。算法通过从最低位到最高位,逐位比较和交换元素,以此实现排序。

function radixSort(arr) {
  let max = Math.max(...arr);

  for (let exp = 1; max / exp > 0; exp *= 10) {
    countingSortByExp(arr, exp);
  }

  return arr;
}

function countingSortByExp(arr, exp) {
  const count = new Array(10).fill(0);

  for (const num of arr) {
    const digit = Math.floor(num / exp) % 10;
    count[digit]++;
  }

  for (let i = 1; i < 10; i++) {
    count[i] += count[i - 1];
  }

  const output = new Array(arr.length);

  for (let i = arr.length - 1; i >= 0; i--) {
    const digit = Math.floor(arr[i] / exp) % 10;
    const index = count[digit] - 1;
    output[index] = arr[i];
    count[digit]--;
  }

  for (let i = 0; i < arr.length; i++) {
    arr[i] = output[i];
  }
}

选择适合的排序算法

在选择排序算法时,需要考虑以下因素:

  • 数据规模 :大规模数据需要使用更高效的算法,