前提
最近在学习快排的知识,发现其核心操作哨兵划分还是有些许难度的,这里做个记录。
哨兵划分
这里先贴出快排的流程。
重点关注哨兵划分的过程。
哨兵划分就是对数组进行处理,将小于哨兵的元素移到哨兵的左侧,将大于哨兵的元素移到哨兵的右侧。在这里,哨兵为数组的首元素。
如上所示,元素1
和0
小于哨兵2
,所以要移动到哨兵左侧;元素4
大于哨兵2
,所以要移动到哨兵右侧。
那么如何编码实现这个过程呢?
解决方法1
仔细观察哨兵划分后的数组,以哨兵为分界,左边的元素都小于哨兵,右边的元素都大于哨兵,但原始数组是没有规律的。
一种可行的方法如下:
- 从数组左边开始找大于哨兵的元素;从数组右边开始找小于哨兵的元素;
- 交换两个元素的位置
- 重复上面的步骤,直到两边在中间相遇为止。
从左边开始找第一个大于哨兵的元素是4
,从右边开始找第一个小于哨兵的元素是0
,所以交换4
和0
的位置。
然后再往下的话,两边在中间就相遇了。此时并没有结束,因为哨兵还没有移动到正确的位置,所以还需将哨兵和相遇位置处的元素进行交换(这里是1)。
整体流程如上所以,下面给出对应的代码。
void swap(vector<int> &nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
int partition(vector<int>& nums, int left, int right)
{
// 以nums[left] 为哨兵
int i = left, j = right;
while (i < j)
{
while (i < j) // 从右边开始找
{
if (nums[j] < nums[left])
{
break; // 找到小于哨兵的元素,就跳出while
}
else
{
j--; // 没有找到,就继续遍历
}
}
while (i < j) // 从左边开始找
{
if (nums[i] > nums[left])
{
break; // 找到大于哨兵的元素,就跳出while
}
else
{
i++; // 没有找到,就继续遍历
}
}
swap(nums, i, j); // 交换元素
}
swap(nums, i, left); // 交换哨兵和中间元素
return i; // 返回哨兵的索引
}
还可以优化下上面的代码:
void swap(vector<int> &nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
int partition(vector<int>& nums, int left, int right)
{
// 以nums[left] 为哨兵
int i = left, j = right;
while (i < j)
{
while (i<j && nums[j] >= nums[left])
{
j--;
}
while (i < j && nums[i]<= nums[left])
{
i++;
}
swap(nums, i, j); // 交换元素
}
swap(nums, i, left); // 交换哨兵和中间元素
return i; // 返回哨兵的索引
}
解决方法2
还有一种方法也可以解决哨兵划分问题。
伪代码如下:
pivot = left; // 哨兵的下标
index = left + 1; // 索引
for(遍历除哨兵外的所有元素)
if(当前元素 < 哨兵)
{
swap(当前元素, nums[index]);
index++;
}
swap(哨兵, nums[index-1]);
这种方法就是先确定小于哨兵的元素,小于哨兵的元素确定好位置后,自然剩下的就是大于哨兵的元素。
代码如下:
void swap(vector<int> &nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
int partition(vector<int>& nums, int left, int right)
{
int index = left + 1;
int pivot = left; // 哨兵索引
for (int i = left+1; i < right; i++)
{
if (nums[i] < nums[pivot])
{
swap(nums[i], nums[index]);
index++;
}
}
swap(nums[pivot], nums[--index]);
return index;
}
参考链接
- https://www.hello-algo.com/chapter_sorting/quick_sort/#1151
- https://visualgo.net/zh/sorting