返回

在 TypeScript 中高效排序:八大排序算法逐一击破

前端

TypeScript 中的八大排序算法

在计算机科学领域,排序算法是必不可少的工具。它可以将数据按特定顺序排列,从而使数据更易于理解、分析和操作。排序算法有很多种,每种算法都有其独特的特点和应用场景。在本文中,我们将探讨八大经典排序算法,并使用 TypeScript 语言实现它们。

1. 插入排序

插入排序是一种简单易懂的排序算法,它的基本思想是将一个元素插入到已经排序好的序列中,使其保持有序。插入排序的平均时间复杂度为 O(n^2),最坏时间复杂度也为 O(n^2),空间复杂度为 O(1)。

function insertionSort(arr: number[]): number[] {
  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;
}

2. 希尔排序

希尔排序是一种改进的插入排序,它通过将数组划分为多个子序列,然后对每个子序列进行插入排序来提高排序效率。希尔排序的平均时间复杂度为 O(n^(3/2)),最坏时间复杂度为 O(n^2),空间复杂度为 O(1)。

function shellSort(arr: number[]): number[] {
  let 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;
}

3. 选择排序

选择排序是一种简单的排序算法,它的基本思想是每次从数组中选择最小的元素,并将其放在数组的开头。选择排序的平均时间复杂度和最坏时间复杂度都为 O(n^2),空间复杂度为 O(1)。

function selectionSort(arr: number[]): number[] {
  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;
      }
    }
    const temp = arr[i];
    arr[i] = arr[minIndex];
    arr[minIndex] = temp;
  }
  return arr;
}

4. 堆排序

堆排序是一种基于二叉堆的数据结构的排序算法。它先将数组构建成一个二叉堆,然后依次弹出堆顶元素,并将其插入到数组的末尾。堆排序的平均时间复杂度为 O(n log n),最坏时间复杂度也为 O(n log n),空间复杂度为 O(1)。

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

  function heapify(arr: number[], i: number): void {
    const left = 2 * i + 1;
    const right = 2 * i + 2;
    let largest = i;
    if (left < arr.length && arr[left] > arr[largest]) {
      largest = left;
    }
    if (right < arr.length && arr[right] > arr[largest]) {
      largest = right;
    }
    if (largest !== i) {
      const temp = arr[i];
      arr[i] = arr[largest];
      arr[largest] = temp;
      heapify(arr, largest);
    }
  }

  buildMaxHeap(arr);
  for (let i = arr.length - 1; i > 0; i--) {
    const temp = arr[0];
    arr[0] = arr[i];
    arr[i] = temp;
    heapify(arr, 0);
  }
  return arr;
}

5. 冒泡排序

冒泡排序是一种简单易懂的排序算法,它的基本思想是将相邻的两个元素进行比较,如果前一个元素大于后一个元素,则交换这两个元素。冒泡排序的平均时间复杂度和最坏时间复杂度都为 O(n^2),空间复杂度为 O(1)。

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

6. 快速排序

快速排序是一种高效的排序算法,它的基本思想是将数组划分为两个子数组,然后递归地对这两个子数组进行排序。快速排序的平均时间复杂度为 O(n log n),最坏时间复杂度为 O(n^2),空间复杂度为 O(log n)。

function quickSort(arr: number[], left: number, right: number): number[] {
  if (left >= right) {
    return arr;
  }
  const pivot = arr[Math.floor((left + right) / 2)];
  let i = left;
  let j = right;
  while (i <= j) {
    while (arr[i] < pivot) {
      i++;
    }
    while (arr[j] > pivot) {
      j--;
    }
    if (i <= j) {
      const temp = arr[i];
      arr[i] = arr[j];
      arr[j] = temp;
      i++;
      j--;
    }
  }
  quickSort(arr, left, j);
  quickSort(arr, i, right);
  return arr;
}

7. 归并排序

归并排序是一种稳定高效的排序算法,它的基本思想是将数组划分为两个子数组,然后对这两个子数组进行排序,最后合并这两个有序的子数组。归并排序的平均时间复杂度和最坏时间复杂度都为 O(n log n),空间复杂度为 O(n)。

function mergeSort(arr: number[]): number[] {
  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: number[], right: number[]): number[] {
  const result: number[] = [];
  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++;