C 语言快速排序

2025年1月12日 | 阅读 7 分钟

快速排序是一种常用的排序算法,因其高效性和有效性而常被其他排序算法所青睐。它通过将一个数组分成两部分进行,一部分包含小于所选基准元素的值,另一部分包含大于基准元素的值。然后,该算法递归地将此过程应用于每个分区,直到整个数组排序完成。

快速排序可用于任何需要排序的场景,例如数据库应用程序、科学计算和 Web 应用程序。当需要快速有效地对大型数据集进行排序时,它经常被使用。快速排序常用的具体用例包括:

  • 对 C、Java 和 Python 等编程语言中的数组进行排序。
  • 对数据库管理系统中的数据库记录进行排序。
  • 对科学计算中的大型数据集进行排序,例如数值模拟和数据分析。
  • 对 Web 应用程序和电子商务平台中的搜索结果进行排序。

总而言之,快速排序是一种用途广泛且被广泛使用的算法,可以应用于各种需要排序的领域。其较低的平均时间复杂度以及执行的简便性使其成为高效排序大型数据集的理想选择。

以下是快速排序的 C 语言代码:

C 语言

输出

Sorted array: 
1 5 6 12 17 25
  • quick_sort 函数接收一个数组 arr,以及要排序的子数组的第一个和最后一个元素的索引 low 和 high。如果 low 小于 high,则函数使用 partition 函数选择一个基准元素,并递归地将 quick_sort 函数应用于基准元素左右两侧的两个子数组。
  • partition 函数接收与 quick_sort 相同的参数,并返回对子数组进行分区后基准元素的索引。它首先选择子数组的最后一个元素作为基准,并初始化一个索引 i 指向子数组的左侧。然后,它遍历子数组,将小于基准的任何元素与 arr[i] 中的元素交换,并递增 i。然后,在返回 i+1 之前,将 arr[i+1] 中的元素与中心元素进行交换。
  • swap 方法会改变两个整数指针的值。
  • 要使用此快速排序实现,只需调用 quick_sort(arr, 0, n-1),其中 arr 是要排序的数组,n 是其长度。
  • 注意,此实现中的基准是子数组的最后一个成员。这是一种简单且常用的方法,但在某些情况下可能导致性能不佳,例如当数组已排序或几乎排序时。在这些情况下,可以通过使用更复杂的基准选择技术来提高效率。此外,此实现使用了递归,在某些情况下可能会导致性能开销。也可以实现快速排序的迭代版本。

特性

  • 快速排序根据基准元素(通常是数组的最后一个元素)将数组分成两部分。
  • 所有小于基准的元素放在一个分区,所有大于基准的元素放在另一个分区,将数组分成两个分区。
  • 该算法对每个分区重复此过程,直到整个数组排序完成。
  • 如果数据已排序或基准元素选择不当,快速排序的最坏情况时间复杂度为 O(n^2)。

优点

  • 快速排序具有快速的平均情况时间复杂度 O(nlogn),使其适用于大型数据集。
  • 它是一种简单易于实现的算法,可以用几行代码实现。
  • 快速排序易于并行化,使其适用于多核和分布式系统。
  • 它是一种就地排序算法,这意味着它不需要额外的内存来存储临时变量或数据结构。

缺点

  • 如果基准元素选择不当或数据已排序,快速排序的最坏情况时间复杂度为 O(n^2)。
  • 它不是一种稳定的排序算法,这意味着它不能保证排序数组中相等元素的相对顺序。
  • 快速排序不适用于排序无法放入内存的大型数据集,因为它需要对数据进行多次遍历。

结论

快速排序是一种流行且高效的排序算法,它通过将数组分成两部分,然后递归地将该过程应用于每个分区,直到整个数组排序完成。其平均情况和最佳情况时间复杂度为 O(nlogn),最坏情况时间复杂度为 O(n^2)。尽管存在最坏情况时间复杂度,但由于其简便性、性能和易于实现,快速排序通常比其他排序算法更受欢迎。

常见问题解答

Q1. 如何有效处理快速排序中的重复元素?

我们可以使用快速排序的三向分割策略来高效处理重复项。当数组包含大量重复值时,这种方法特别有用,因为它可以最大限度地减少产生严重不平衡子数组的可能性,这可能会导致排序算法性能下降。

然而,当存在大量重复项时,排序可能会变得效率低下,因为此方法并未明确考虑重复项。三向分区方法解决了这个问题,它为等于基准的元素添加了一个第三段。为此,使用所有三个索引来跟踪小于、等于和大于分区的最外层边界,这些索引在划分值数组时会发生变化。

这种方法有几个实际好处。首先,通过减少无用的比较和交换的总量,它提高了包含大量重复项的集合的排序效率。其次,它还确保了较小且更平衡的子数组用于执行递归排序步骤,从而提高了快速排序的整体性能。为了处理这些分区的递归排序,通过定义一个使用三个索引管理三个分区的分区函数来更新快速排序函数。这就是该方法在 C 中执行的方式。这个微小的改动增强了算法处理重复项的能力。实现三向分割可确保即使在处理包含大量重复信息的数组时,快速排序也可靠且高效。

Q2. 快速排序的平均时间复杂度是多少?

答案是 O(n log n)。

Q3. 快速排序的最坏情况时间复杂度是多少?

O(n^2)。

Q4. 如何提高快速排序的功能?

使用三向分区本质上是将数组分成三个单独的段,小于基准的项、等于基准的元素以及大于基准的元素,这是一种有效的改进。这种方法可确保有效管理重复的组件,从而产生更均匀分布的分区,并减少所需的比较和交换的总量。

这个微不足道的调整提高了算法处理重复元素的能力。通过实现三向分割,我们可以确保即使在处理大量重复信息的数组时,快速排序也可靠且高效。

实施更复杂的技术,包括“三数取中”或随机基准选择,有时用于避免持续将第一个或最后一个元素选为基准,这可能导致在已排序或几乎排序的集合上出现糟糕的性能。通过将基准选为数组的第一个、中间和最后一个项的中位数,“三数取中”方法有助于创建更均匀分布的分区,并减少遇到最坏情况时间复杂度 O(n 2) 的可能性。除了消除可能影响性能的趋势外,随机选择基准还提供了一种简单但实质性的方法来提高算法性能。

Q5. 快速排序的基本功能是什么?

根据基准组件划分数组。

Q6. 在快速排序中,如何选择基准元素?

基准点可以通过多种方式选择,包括作为第一个、最后一个或随机选择的元素。

Q7. 快速排序的基本步骤是什么?

选择一个基准;将整个数组划分成更小的子数组,并迭代地对子数组围绕基准进行排序。


下一个主题C 语言中的 realloc