返回

快速排序的思路与优化改进:清晰易懂,高效实用

见解分享

快速排序:理念与优化

快速排序是一种分而治之的排序算法,它以其速度和效率而闻名。它使用分治法将一个大数组分解成更小的数组,直到每个小数组只剩下一个元素。然后,它将这些小的已排序数组合并成一个更大的已排序数组。

快速排序的核心思想是基于枢纽元素的分割。枢纽元素是数组中的一个元素,它将数组划分为两个部分:比枢纽元素小的元素和比枢纽元素大的元素。

快速排序算法的步骤如下:

  1. 选择数组中的一个元素作为枢纽元素。
  2. 将数组划分为两部分:比枢纽元素小的元素和比枢纽元素大的元素。
  3. 对两个子数组分别进行快速排序。
  4. 将排序后的子数组合并成一个大的已排序数组。

优化快速排序

为了提高快速排序的效率,可以进行以下优化:

1. 三路分割

标准的快速排序使用两路分割,即只考虑比枢纽元素大或小的元素。三路分割则引入了额等于枢纽元素的元素,从而将数组划分为三部分:比枢纽元素小、等于枢纽元素和比枢纽元素大。

2. 随机选择枢纽元素

在标准的快速排序中,通常选择第一个或最后一个元素作为枢纽元素。然而,如果数组已经部分有序,这种选择可能导致排序效率降低。随机选择枢纽元素可以避免这种问题。

3. 插入排序优化

对于小数组,插入排序比快速排序更有效率。当子数组的大小小于某个阈值时,可以切换到插入排序。

4. 尾递归优化

尾递归优化是一种将递归调用放在函数末尾的编译器优化技术。它可以消除函数调用的开销,从而提高代码的性能。

C 语言实现

#include <stdio.h>
#include <stdlib.h>

void swap(void *a, void *b, size_t size) {
  char temp[size];
  memcpy(temp, a, size);
  memcpy(a, b, size);
  memcpy(b, temp, size);
}

int compare(const void *a, const void *b) {
  return *(int *)a - *(int *)b;
}

void quickSort(void *arr, size_t size, size_t elemSize, int (*cmp)(const void *, const void *)) {
  if (size <= 1) {
    return;
  }

  // 选择枢纽元素
  size_t pivotIndex = rand() % size;
  swap(arr + pivotIndex * elemSize, arr, elemSize);

  // 三路分割
  size_t left = 0;
  size_t right = size - 1;
  size_t equal = 0;
  while (equal <= right) {
    int cmpResult = cmp(arr + equal * elemSize, arr);
    if (cmpResult < 0) {
      swap(arr + left * elemSize, arr + equal * elemSize, elemSize);
      left++;
      equal++;
    } else if (cmpResult > 0) {
      swap(arr + right * elemSize, arr + equal * elemSize, elemSize);
      right--;
    } else {
      equal++;
    }
  }

  // 递归排序
  quickSort(arr, left, elemSize, cmp);
  quickSort(arr + (right + 1) * elemSize, size - (right + 1), elemSize, cmp);
}

int main() {
  int arr[] = {5, 3, 1, 2, 4};
  size_t size = sizeof(arr) / sizeof(arr[0]);

  quickSort(arr, size, sizeof(int), compare);

  for (size_t i = 0; i < size; i++) {
    printf("%d ", arr[i]);
  }
  printf("\n");

  return 0;
}