2026.02.13

  1. 快速排序看代码练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <vector>
#include <iostream>


int partition(vector<int>& nums,int low,int high)
{
int pivot=nums[high];
int i=low;

for(int j=low,j<high;j++)
{
if(nums[j]<=pivot)
{
swap(nums[i],nums[j]);
i++;
}
}

swap(nums[i],nums[high]);
return i;
}



void quickSort(vector<int>& nums,int low,int high)
{
if(low<high)
{
int p=partition(nums,low,high);
quickSort(nums,low,p-1);
quickSort(nums,p+1,high);
}
}

这是Lomuto分区的写法。思路如下:

让i先待在最左边,它代表的是小于区的右边界,也就是下一个<= pivot 的元素应该放的位置。

然后,j从low开始遍历,开始处理每一个数。如果nums[j]的值小于pivot,那么应该把它放到i那个位置。然后i再向右,为下一次赋值做准备。

发现,遍历的过程中,j是不到high的。j走完之后,i待的地方的值肯定是大于pivot的,这时候把最后一个也就是我们的pivot和该值交换,也不会有问题。

终于梳理了一遍搞懂了。再写两边巩固肌肉记忆:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>
#include <vector>


int partition(vector<int>& nums,int low,int high)
{
int i=low;


int pivot=nums[high];

for(int j=low;j<high;j++)
{
if(nums[j]<=pivot)
{
swap(nums[i],nums[j]);
i++;
}
}

swap(nums[i],nums[high]);

return i;
}


void quickSort(vector<int>& nums,int low,int high)
{
if(low<high)
{
int pivot=partition(nums,low,high);
quickSort(nums,low,pivot-1);
quickSort(nums,pivot+1,high);
}


}

下面学习一下hoare分区:

这个算法大致看了一眼,循环次数要比lomuto要少,而且左右都可以有=,好像更均衡。

先抄写学习一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <vector>



int partition_hoare(vector<int>& nums,int low,int high)
{
int pivot=nums[low+(high-low)/2];

int i=low-1;
int j=high+1;

while(true)
{
do i++ ;while(nums[i]<pivot);
do j-- ;while(nums[j]>pivot);
if(i>=j)
{
return j;
}
swap(nums[i],nums[j]);
}
}

这个算法就是在夹逼操作。i和j先移动再判断,好理解一些。

每一个whiletrue里,i移动,最后停在一个>=pivot的位置上。j移动,最后停在一个<=pivot的位置上。

二者交换即可。这能让=pivot的能够分布在两边。

判断交错的时候也需要注意一下是i>=j。这个时候j指向左半部分的最后一个元素,i指向右半部分的第一个元素。返回j就行了,后面递归就是(low,j)和(j+1,high)。此时pivot不需要归位!

Hoare快是因为它一次交换同时修复两个元素的位置错误,而Lomuto一次交换只处理一个。

Lomuto是单向扫描:发现一个≤pivot的就往左边塞,被换到右边的元素不检查它该不该在右边。
Hoare是双向夹逼:左边找到该去右边的,右边找到该去左边的,一次交换两个元素各归其位。

所以Hoare的交换次数≈Lomuto的一半,重复元素越多差距越大。

把hoare再练习写一遍:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


int partition_hoare(vector<int>& nums,int low,int high)
{
int pivot=nums[low+(high-low)/2];
int i=low-1;
int j=high+1;

while(true)
{
do i++; while(nums[i]<pivot);
do j--; while(nums[j]>pivot);
if(i>=j)
{
return j;
}
swap(nums[i],nums[j]);
}
}

void quickSort_Hoare(vector<int>& nums,int low,int high)
{
if(low<high)
{
int p=partition_hoare(nums,low,high);
quickSort_Hoare(nums,low,p);
quickSort_Hoare(nums,p+1,high);
}
}