待排数字序列:
4 2 0 1 2
算法大致思想:
实现方式一:
初始化中心轴Pivot为2,最左排序边界为Left = 0, 最右边界为Right = Size - 1(指向末尾元素)
第一轮递归后:
以Pivot为分界线,左序列元素 <= Pivot, 右序列元素 >= Pivot
序列更新为: 2 1 0 2 4 分为左右2部分
左序列为:
右序列为:
分别对左右序列递归执行上述二分排序直至不可再分,
即可得整个有序数组:
void QuickSort(int* arr, int Left, int Right)
{
if (Left >= Right) return;//递归出口,当分到不可再分时退出排序
int i = Left, j = Right, Pivot = arr[Right];
while (i < j)
{
while (arr[i] < Pivot && i <= j)
{
i++;
}
while (arr[j] > Pivot && i <= j)
{
j--;
}
if (i <= j)
{
swap(arr[i], arr[j]);
i++;
j--;
}
}
QuickSort(arr, i, Right);//执行到这里时,必有 i != j
QuickSort(arr, Left, j);
}
实现方式二:
与实现方式一不同的是,该方法使用双指针单向向右移动遍历序列,先看代码:
int Partition(vector<int>& arr, int Left, int Right) {
int j = Left, Pivot = arr[Left];
for (int i = Left + 1; i <= Right; i++) {
if (arr[i] < Pivot) {
j++;
swap(arr[i], arr[j]); //使得arr[<=j && j != Left] < Pivot
}
}
swap(arr[Left], arr[j]); //将Pivot放到左区间的右边界,则有Pivot < arr[>j], Pivot > arr[<j]
return j;
}
void QuickSort(vector<int>& arr, int Left, int Right) {
if (Left > Right) return;
int mid = Partition(arr, Left, Right);
QuickSort(arr, Left, mid - 1);
QuickSort(arr, mid + 1, Right);
}
其中,j索引用来指向左序列的最右边界(分界线),i索引用于遍历整个序列,第 4 5 6行代码
if (arr[i] < Pivot) {
j++;
swap(arr[i], arr[j]);
}
当 arr[i] >= Pivot 时,i 右移,而当 arr[i] < Pivot 时,更新j值的同时将< Pivot的arr[i] 与更新后的arr[j] 交换,使得 arr [j] 必有 arr[j] < Pivot , 从而经过循环后使得左序列 arr[<=j && j != Left] < Pivot (此句只描述逻辑,不遵循C++语法)
在循环后,
swap(arr[Left], arr[j]);
使得j 指向左序列的右边界,同时也是整个序列的分界线,有 Pivot < arr[>j], Pivot <= arr[<=j]