返回

排序算法解码:常见算法深入探究与直观示例

前端

JavaScript排序算法深度解析

在计算机科学的浩瀚领域,排序算法扮演着至关重要的角色,它负责将无序的数据集合按一定规则排列,从而方便后续处理和分析。作为Web开发的基石,JavaScript提供了丰富的排序算法,本文将深入剖析这些算法的原理、代码实现、复杂度分析,并通过例题展示,帮助你全面掌握排序算法的精髓。

排序算法简介

排序算法的目标是将一个无序的数据集合(数组或列表)按照特定顺序重新排列。常见的排序算法包括:

  • 冒泡排序
  • 选择排序
  • 插入排序
  • 希尔排序
  • 快速排序
  • 归并排序
  • 堆排序

冒泡排序

冒泡排序是一种简单直观的算法,它通过不断比较相邻元素并进行交换,将最大的元素逐个“浮”到数组末尾,从而达到排序的目的。其代码实现如下:

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

选择排序

选择排序是一种相对高效的排序算法,它通过不断在剩余元素中找到最小值并与当前元素交换,将最小元素逐个移动到数组开头,从而实现排序。其代码实现如下:

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

插入排序

插入排序是一种较为直观的排序算法,它通过将元素逐个插入到已排序的数组中,从而达到排序的目的。其代码实现如下:

function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    let currentElement = arr[i];
    let j = i - 1;
    while (j >= 0 && currentElement < arr[j]) {
      arr[j + 1] = arr[j];
      j--;
    }
    arr[j + 1] = currentElement;
  }
  return arr;
}

希尔排序

希尔排序是一种改良的插入排序,它通过将数组划分为多个子序列,并对每个子序列进行插入排序,从而提高排序效率。其代码实现如下:

function shellSort(arr) {
  let gap = Math.floor(arr.length / 2);
  while (gap > 0) {
    for (let i = gap; i < arr.length; i++) {
      let currentElement = arr[i];
      let j = i - gap;
      while (j >= 0 && currentElement < arr[j]) {
        arr[j + gap] = arr[j];
        j -= gap;
      }
      arr[j + gap] = currentElement;
    }
    gap = Math.floor(gap / 2);
  }
  return arr;
}

快速排序

快速排序是一种高效的分治排序算法,它通过选取一个枢轴元素,将数组划分为两个子数组,并对每个子数组递归应用快速排序,从而达到排序的目的。其代码实现如下:

function quickSort(arr) {
  if (arr.length <= 1) {
    return arr;
  }
  let pivot = arr[0];
  let left = [];
  let 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)];
}

归并排序

归并排序是一种稳定的排序算法,它通过将数组分为多个子数组,并对每个子数组进行递归排序,再将排序后的子数组合并,从而达到排序的目的。其代码实现如下:

function mergeSort(arr) {
  if (arr.length <= 1) {
    return arr;
  }
  let mid = Math.floor(arr.length / 2);
  let left = mergeSort(arr.slice(0, mid));
  let right = mergeSort(arr.slice(mid));
  return merge(left, right);
}

function merge(left, right) {
  let merged = [];
  let leftIndex = 0;
  let rightIndex = 0;
  while (leftIndex < left.length && rightIndex < right.length) {
    if (left[leftIndex] < right[rightIndex]) {
      merged.push(left[leftIndex]);
      leftIndex++;
    } else {
      merged.push(right[rightIndex]);
      rightIndex++;
    }
  }
  return [...merged, ...left.slice(leftIndex), ...right.slice(rightIndex)];
}

堆排序

堆排序是一种利用堆数据结构实现的排序算法,它通过将数组构建成一个最大堆,然后不断将堆顶元素与最后一个元素交换,再重新调整堆,从而达到排序的目的。其代码实现如下:

function heapSort(arr) {
  buildMaxHeap(arr);
  for (let i = arr.length - 1; i > 0; i--) {
    swap(arr, 0, i);
    heapify(arr, 0, i);
  }
  return arr;
}

function buildMaxHeap(arr) {
  for (let i = Math.floor(arr.length / 2) - 1; i >= 0; i--) {
    heapify(arr, i, arr.length);
  }
}

function heapify(arr, root, size) {
  let largest = root;
  let left = 2 * root + 1;
  let right = 2 * root + 2;
  if (left < size && arr[left] > arr[largest]) {
    largest = left;
  }
  if (right < size && arr[right] > arr[largest]) {
    largest = right;
  }
  if (largest !== root) {
    swap(arr, root, largest);
    heapify(arr, largest, size);
  }
}

function swap(arr, i, j) {
  let temp = arr[i];
  arr[i] = arr[j];
  arr[j] = temp;
}

复杂度分析

以下是对上述排序算法的复杂度分析:

算法 最好复杂度 最坏复杂度 平均复杂度 空间复杂度
冒泡排序 O(n) O(n²) O(n²) O(1)
选择排序 O(n²) O(n²) O(n²) O(1)
插入排序 O(n) O(n²) O(n²) O(1)
希尔排序 O(n log n) O(n²) O(n log n) O(1)
快速排序 O(n log n) O(n²) O(n log n) O(log n)
归并排序 O(n log n) O(n