快速排序代码踩坑
踩坑原因
写快排代码时,核心代码块在移动数组的左右标号时。自己没有注意到利用while循环,移动左标号和移动右标号的先后顺序会对排序结果造成影响。
错误代码块
这里使用的是数组的最左标号作为参考值,将区间内比参考值小的都放在其左侧,比参考值大的都放在参考值右侧。
void QuickSort(std::vector<int> &nums, int l, int r)
{
if (l >= r)
return;
int left{l}, right{r};
while (left < right)
{
while (left < right && nums[left] <= nums[l])
++left;
while (right > left && nums[right] >= nums[l])
--right;
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
int temp = nums[l];
nums[l] = nums[left];
nums[left] = temp;
QuickSort(nums, l, left - 1);
QuickSort(nums, left + 1, r);
}
注意此时先移动左标号left,再移动右标号right,最后left==right终止循环时,nums[left]==nums[right],此数是可能大于最左侧的参考值的。则跳出外层的while循环后,会把此大于参考值的数nums[left]换到数组最左侧。
最简单的例子可以参考{1,2,3},若先移动左标号,最终left==right==1,即停在中间的数值2,然后交换1和2的位置,显然不满足快排。
正确代码块
先移动右标号,再移动左标号,最终会停在一个小于等于参考值的地方,并被换到最左侧。
void QuickSort(std::vector<int> &nums, int l, int r)
{
if (l >= r)
return;
int left{l}, right{r};
while (left < right)
{
while (right > left && nums[right] >= nums[l])
--right;
while (left < right && nums[left] <= nums[l])
++left;
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
int temp = nums[l];
nums[l] = nums[left];
nums[left] = temp;
QuickSort(nums, l, left - 1);
QuickSort(nums, left + 1, r);
}
int main()
{
std::vector<int> nums{10, 23, 32, 33, 6, 34, 99, 1, 96, 2};
int sz = nums.size();
QuickSort(nums, 0, sz - 1);
for (auto &num : nums)
std::cout << num << " ";
std::cout << std::endl;
return 0;
}
最终输出 1 2 6 10 23 32 33 34 96 99
注释
若以区间最右侧的数作为参考值,则要先移动左标号,再移动右标号。