交换排序

算法思想

交换排序的基本思想是:通过比较待排序序列中两个元素的关键字,如果它们的顺序不符合要求,就交换它们的位置,直到整个序列达到有序状态。

冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法。

  1. 基本思想:它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复进行的,直到没有再需要交换,也就是说该数列已经排序完成。
  2. 算法过程
    • 一趟冒泡:从序列的第一个元素开始,依次比较相邻的两个元素。如果前一个元素大于后一个元素,则交换它们的位置。这样,每一趟冒泡都会将当前未排序序列中最大的元素“冒泡”到其最终位置。
    • 重复过程:重复上述过程 趟(对于一个长度为 的序列),直到所有元素都排好序。
  3. 性能分析
    • 时间复杂度
      • 最好情况(序列已经有序):。此时,第一趟冒泡时没有发生任何交换,算法可以提前终止。
      • 最坏情况(序列逆序):。需要进行 趟冒泡,每趟比较和交换的次数大致为
      • 平均情况
    • 空间复杂度,因为它只需要常数级别的额外空间来存储临时变量。
    • 稳定性:冒泡排序是稳定的排序算法。如果两个元素的关键字相等,它们相对位置不会改变。

快速排序

快速排序(Quick Sort)是一种高效的排序算法,基于分治策略。

  1. 基本思想
    • 选择基准(Pivot):从待排序序列中选择一个元素作为“基准”(pivot)。
    • 划分(Partition):重新排序序列,将所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准后面(相等的可以放在任意一边)。在这个划分结束之后,该基准就处于其最终的正确位置上。
    • 递归:递归地对基准值前和基准值后的两个子序列进行快速排序。
  2. 算法过程
    • 选择基准元素:通常选择序列的第一个、最后一个或中间元素作为基准。也可以随机选择。
    • 划分操作
      • 设基准值为 pivot
      • 使用两个指针 iji 从左向右扫描,j 从右向左扫描。
      • i 找到第一个大于 pivot 的元素,j 找到第一个小于 pivot 的元素。
      • 交换 arr[i]arr[j]
      • ij 相遇时,将 pivot 放到 ij 相遇的位置。
    • 递归调用:对基准元素左右两边的子序列重复上述过程。
  3. 性能分析
    • 时间复杂度
      • 最好情况(每次划分都将序列均匀分成两部分):。例如,每次都选择中位数作为基准。
      • 最坏情况(每次划分都产生一个空子序列和一个 长度的子序列,例如序列已经有序或逆序,且选择第一个/最后一个元素作为基准):
      • 平均情况
    • 空间复杂度(平均情况)到 (最坏情况),取决于递归深度,通常是栈空间消耗。
    • 稳定性:快速排序是不稳定的排序算法。在划分过程中,可能会交换相等元素的相对位置。

采用 O(n) 空间的快排

采用 O(1) 空间的快排

递归地处理两个子区间

效率分析

划分操作对性能的影响

划分操作是快速排序的核心,其效率直接影响整个算法的性能。

  1. 基准选择
    • 固定选择(如选择第一个最后一个元素):在输入序列部分有序或完全有序时,可能导致划分不均匀,退化为最坏情况
    • 随机选择:可以有效避免最坏情况的发生,使平均性能保持在
    • 三数取中法:选择序列的第一个、中间和最后一个元素的中位数作为基准。这种方法可以提高划分的均匀性,减少出现最坏情况的概率。
  2. 划分过程
    • 双指针法:常用的划分方法,通过两个指针从两端向中间扫描并交换元素,效率较高。
    • 单指针法(Hoare Partition Scheme 或 Lomuto Partition Scheme):也可以实现划分,但双指针法通常被认为更健壮,且在某些情况下能更好地处理重复元素。
  3. 划分均匀性
    • 理想的划分是将序列分成大小相等的两部分。
    • 划分越不均匀,递归深度越大,算法性能越接近
    • 划分越均匀,递归深度越小,算法性能越接近
  4. 重复元素处理
    • 如果序列中包含大量重复元素,传统的划分方法可能导致划分不均匀(例如,所有重复元素都分到一边),从而降低效率。
    • 三向切分(Dutch National Flag Problem):一种改进的快速排序,将序列划分为小于基准、等于基准和大于基准的三个部分。这对于包含大量重复元素的序列能显著提高性能,避免了对相等元素的重复处理,使算法在处理相同元素时效率更高。
    • 这种方法将时间复杂度降至 对于包含大量重复元素的序列。
  5. 小规模子序列处理
    • 当子序列的长度较小(例如小于 10-20 个元素)时,快速排序的递归开销可能大于简单的排序算法(如插入排序)。
    • 优化方法是当子序列长度达到一定阈值时,停止快速排序的递归,转而使用插入排序对这些小规模子序列进行排序。这种混合排序策略可以提高整体性能。