在上一章我们讲解了 快速排序基石之荷兰国旗问题
这一章我们在此基础上继续扩展
题目一:
给定一个数组 arr,一个数 num,请把小于等于 num 的数放在数组的左边,等于 num 的数放在数组中间,大于 num 的数放在数组的右边。
要求额外空间复杂度 O(1),时间复杂度 O(N)
思路:
以 num 为界把数组分为三部分:
1. 左侧 <= num 区域
2. 中间 == num 区域
3. 右侧 >= num 区域
那么我们可以设定两个边界的 idx,当前元素与 num 进行比较:
1. 如果 [i] < num,右边界右侧的元素与 [i] 之间的元素是 >= num 的元素,所以我们首先要将 [i] <> 右边界右侧元素进行交换,然后把边界右扩
2. 如果 [i] == num,那么边界不动,直接判定下一个元素
3. 如果[i] > num,左边界左侧的元素与当前元素交换,当前元素应该被左边界包括,然后左边界左扩。交换完的新元素重新进行逻辑 123 的判定
图示:
1. 初始状态,less = -1,more = len,当前元素 = 3,小于 5,与 less+1 元素交换(3)
2. 当前元素 == 5,跳过,判定下一个元素 6
3. 元素 6 大于 5,应该放到大于范围,与 more - 1 元素交换 ,左边界左扩
4. 新交换的元素还未做任何判定,依照逻辑继续进行
5. 后续同理,直到当前元素 == 左边界
代码:
void sortbynum2(int *arr, int len, int num)
{
int less = -1;
int more = len;
int i = 0;
while(i < more)
{
if(arr[i] < num) // [i] <= num
{
swap(arr, i, less+1);
less++;
i++;
}
else if(arr[i] == num)
{
i++;
}
else
{
swap(arr, i, more-1);
more--;
}
}
}
通过这种方式不断的将 小于边界右扩,大于边界左扩,剩下部分就是中间相等区域
下一章我们正式引入 快速排序,看看为什么国旗问题的解放是其基石