手写 “快速排序”

在我们写算法中,如果需要高效的、原地的排序算法,这时候我们就可以用到快速排序

概念

快速排序(Quick Sort)是一种常用的排序算法,用于将一组数据按照一定的顺序进行排列。它的 基本思想 是通过分治的策略将原始数组分割成较小的子数组,然后递归地对子数组进行排序,最终将这些子数组合并起来得到有序数组。

这个算法的 “快速” 体现在以下几个方面:

  • 快速的平均时间复杂度: 在平均情况下,快速排序的时间复杂度为O(nlogn),性能非常优秀。
  • 快速的排序过程: 快速排序采用了分而治之的策略,通过不断地分割和排序来实现快速排序,因此排序的过程相对较快。
  • 快速的原地排序: 快速排序通常是原地排序的,不需要额外的存储空间。

总的来说,快速排序是一种高效的、原地的排序算法,虽然在最坏情况下时间复杂度可能较高,但在实际应用中,它的性能仍然非常出色。

那么它排序的步骤呢 (算法描述)

  1. 选择一个基准值(pivot),通常选择第一个元素作为基准值
  2. 将数组中小于等于基准值的元素放到基准值的左边,大于基准值的元素放到右边,基准值所在的位置通常称为分区点(pivot position)
  3. 递归地对基准值左右两侧的子数组进行快速排序
  4. 重复上述步骤,直到所有的子数组都变得很小,排序完成

快速排序的关键在于分区操作,即如何将小于等于基准值和大于基准值的元素分开。一般情况下,可以使用双指针法或者递归实现来进行分区操作。

快速排序的时间复杂度为O(nlogn),
在平均情况下性能很好,
但最坏情况下可能达到O(n^2)。
然而,由于其原地排序和非稳定性,快速排序在实际应用中仍然被广泛使用

function quickSort(arr, left, right):
    if left < right:
        pivotIndex = partition(arr, left, right) // 获取基准值的位置
        quickSort(arr, left, pivotIndex - 1) // 对基准值左边的子数组进行快速排序
        quickSort(arr, pivotIndex + 1, right) // 对基准值右边的子数组进行快速排序

function partition(arr, left, right):
    pivot = arr[left] // 选择第一个元素作为基准值
    i = left + 1
    j = right

    while i <= j:
        // 找到左边第一个比基准值大的元素
        while i <= j and arr[i] <= pivot:
            i = i + 1
        // 找到右边第一个比基准值小的元素
        while i <= j and arr[j] > pivot:
            j = j - 1
        if i <= j:
            swap(arr, i, j) // 交换左右两个元素

    swap(arr, left, j) // 将基准值放到正确的位置上
    return j // 返回基准值的位置

function swap(arr, i, j):
    temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp

这个伪代码描述了快速排序的基本思想和分区操作。你可以根据这个描述来实现快速排序算法。

实现

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)]; // 递归处理左右两部分,并将结果合并
}

// 测试
const arr = [3, 6, 8, 10, 1, 2, 1];
const sortedArr = quickSort(arr);
console.log(sortedArr); // 输出排序后的数组

这段代码实现了快速排序算法。在这个示例中,我们选择数组中的第一个元素作为基准值(pivot),然后将数组中比基准值小的元素放到左边,比基准值大的元素放到右边,最后递归地对左右两部分进行排序,直到每个子数组的长度都不大于1。

function quickSort(arr, left = 0, right = arr.length - 1) {
  if (left >= right) {
    return;
  }

  const pivot = partition(arr, left, right); // 找到基准值的位置
  quickSort(arr, left, pivot - 1); // 递归处理左边的子数组
  quickSort(arr, pivot + 1, right); // 递归处理右边的子数组
}

function partition(arr, left, right) {
  const pivotValue = arr[left]; // 选择第一个元素作为基准值
  let i = left + 1;
  let j = right;

  while (i <= j) {
    while (i <= j && arr[i] < pivotValue) {
      i++; // 找到左边第一个比基准值大的元素
    }
    while (i <= j && arr[j] > pivotValue) {
      j--; // 找到右边第一个比基准值小的元素
    }
    if (i <= j) {
      [arr[i], arr[j]] = [arr[j], arr[i]]; // 交换左右两个元素
      i++;
      j--;
    }
  }

  [arr[left], arr[j]] = [arr[j], arr[left]]; // 将基准值放到正确的位置上
  return j; // 返回基准值的位置
}

// 测试
const arr = [3, 6, 8, 10, 1, 2, 1];
quickSort(arr);
console.log(arr); // 输出排序后的数组

这种实现方式与上面的示例有所不同,它使用了双指针的方式来找到基准值的位置,并且是在原数组上进行操作的。

无论哪种实现方式,快速排序算法的核心思想都是通过分治的策略将问题规模逐步缩小,最终得到一个有序的结果。希望这能帮助你更好地理解快速排序算法的实现过程。

你可能感兴趣的:(算法,算法,数据结构)