双路快速排序学习笔记

原理简介

双路快速排序是一种常见的排序算法,其基本思想是通过分治法将待排序的序列分成两部分,然后对这两部分再分别进行排序,最终将整个序列排序。

具体而言,快速排序先选定一个枢轴值,然后将序列中小于枢轴值的元素放在枢轴值的左侧,大于枢轴值的元素放在右侧。接着对左右两侧的子序列分别进行递归排序,直到整个序列都有序。

与传统的快速排序不同的是,在双路快速排序中,我们选取了两个指针i和j分别从序列的左右两端开始扫描,并且保证左边的指针i所指向的元素小于等于枢轴值,右边的指针j所指向的元素大于等于枢轴值,然后交换i和j指向的元素。当i和j相遇时,遍历完成,此时i左侧的元素均小于等于枢轴值,右侧的元素均大于等于枢轴值。然后将枢轴值与i指向的元素交换,此时枢轴值就位于数组的中间位置,左侧的元素均小于等于枢轴值,右侧的元素均大于等于枢轴值。接下来递归处理左半部分和右半部分即可。

算法流程

  1. 选定枢轴值pivot,从左端l开始和右端r开始各设置一个指针i和j。
  2. 一直移动i,直到找到一个元素大于等于枢轴值pivot为止。
  3. 一直移动j,直到找到一个元素小于等于枢轴值pivot为止。
  4. 如果此时i<=j,则交换a[i]和a[j]的值,然后i向右移动一位,j向左移动一位。
  5. 重复步骤2~4,直到i>j。最后再将pivot与a[j]交换,完成一次排序。
  6. 对左右两个子序列分别重复步骤1~5,直到所有子序列都有序。

Python 代码实现

pythonCopy Code
def quick_sort(nums, left, right): if left >= right: return pivot = nums[left] i = left + 1 j = right while True: while i <= j and nums[i] < pivot: i += 1 while i <= j and nums[j] > pivot: j -= 1 if i > j: break nums[i], nums[j] = nums[j], nums[i] i += 1 j -= 1 nums[left], nums[j] = nums[j], nums[left] quick_sort(nums, left, j-1) quick_sort(nums, j+1, right) nums = [3, 6, 2, 8, 4, 1, 5, 7] quick_sort(nums, 0, len(nums)-1) print(nums)

实例演示

我们用下面的例子来演示双路快速排序的过程:

Copy Code
[3, 6, 2, 8, 4, 1, 5, 7]

首先以3为枢轴值,左指针i从索引1开始扫描,右指针j从索引6倒着扫描:

Copy Code
i pivot j ↓ ↓ ↓ [3, 6, 2, 8, 4, 1, 5, 7]

移动i,找到第一个大于等于3的元素6,移动j,找到第一个小于等于3的元素1,然后交换i和j指向的元素:

Copy Code
i pivot j ↓ ↓ ↓ [1, 6, 2, 8, 4, 3, 5, 7]

接着继续移动i和j,直到i>j,此时交换pivot和aj

Copy Code
pivot ↓ [1, 2, 3, 8, 4, 6, 5, 7]

现在我们已经完成了第一次排序,接下来对左右两边的子序列分别进行排序。左半部分是[1,2]和右半部分是[8,4,6,5,7]。以左半部分为例,以2为枢轴值,继续进行双路快速排序:

Copy Code
pivot ↓ [1, 2, 3, 8, 4, 6, 5, 7]

移动i和j,交换i和j指向的元素:

Copy Code
pivot ↓ [1, 2, 3, 8, 4, 6, 5, 7] i j ↓ ↓

再移动i和j,直到i>j,最终交换pivot和a[j]:

Copy Code
pivot ↓ [1, 2, 3, 8, 4, 6, 5, 7] i/j ↓ [1, 2, 3, 5, 4, 6, 8, 7]

左半部分已经排好序了,右半部分依次执行相同的操作即可。最终得到有序序列:

Copy Code
[1, 2, 3, 4, 5, 6, 7, 8]