我试过用算法导论的写法做215数组中最大的第K个元素,但是最后一个用例死活过不去,所以以后的快排都用官方的写法。
先来看看算法导论里快排的写法
public static void quickSort(int[] A, int p, int r) {
if (p < r) {
int q = partition_1(A, p, r);
quickSort(A, p, q - 1);
quickSort(A, q + 1, r);
}
public static int partition_1(int[] A, int p, int r) {
int x = A[r];
int i = p - 1;
for (int j = p; j < r; j++) {
if (A[j] <= x) {
i++;
swap(A, i, j);
}
}
swap(A, i + 1, r);
return i + 1;
}
算法思路
使用四个指针,p和r为当前排序(递归)的左右边界,i是“边界”指针,j是工作指针。
如果j遇到小于等于pivot的元素,与i进行交换,这样,小的就跑到左边,大的就跑到右边了。
-
针对于以
A[r],也就是每次递归中,最后一个元素为枢轴(pivot),i初始化为p - 1,j初始化为p。i的含义:swap后,[p, i]都是<= pivot的元素,[i + 1, j]都是比> pivot的元素,pivot (A[r])是大的元素,放在i + 1的位置。 -
针对于以
A[p],也就是每次递归中,第一个元素为枢轴(pivot),i初始化为p,j初始化为p + 1。i的含义:swap后,[p, i]都是<= pivot的元素,[i + 1, j]都是> pivot的元素,pivot (A[p])是小的元素,放在i的位置。
下图只展示了以A[r]为pivot的情况,浅灰色表示比pivot小的元素,深灰色表示比pivot大的元素。
图中A[j] <= A[i] 全部替换为 A[j] <= A[r]
再来看看官方题解里快排的写法
为什么往左递归是(p, q),往右递归是(q + 1, r)呢?因为partition的终止条件是while(i < j),终止时必定会有j <= i,意味着j有可能恰好位于pivot的位置,也有可能位于pivot - 1的位置(此时pivot指的是下标),没错,就是这么吊。所以为了避免当j == pivot - 1,而q = q - 1,也就是右边界变成pivot - 1 - 1,所以往左递归是(p, q),而不是(p, q - 1)
public static void quickSort(int[] A, int p, int r) {
if (p < r) {
int q = partition_2(A, p, r);
quickSort(A, p, q);
quickSort(A, q + 1, r);
}
}
public static int partition_2(int[] nums, int left, int right) {
// int randomIndex = left + random.nextInt(right - left + 1);
// swap(nums, randomIndex, right);
int pivot = nums[left], i = left - 1, j = right + 1;
while (i < j) {
do {
i++;
} while (nums[i] < pivot);
do {
j--;
} while (nums[j] > pivot);
if (i < j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
return j;
}
忽略target