不同快速排序写法的边界条件有什么不同?

115 阅读2分钟

我试过用算法导论的写法做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;
}

算法思路
使用四个指针,pr为当前排序(递归)的左右边界,i是“边界”指针,j是工作指针。 如果j遇到小于等于pivot的元素,与i进行交换,这样,小的就跑到左边,大的就跑到右边了。

  • 针对于以A[r],也就是每次递归中,最后一个元素为枢轴(pivot),i初始化为p - 1j初始化为pi的含义:swap后,[p, i]都是<= pivot的元素,[i + 1, j]都是比> pivot的元素,pivot (A[r])是大的元素,放在i + 1的位置。

  • 针对于以A[p],也就是每次递归中,第一个元素为枢轴(pivot),i初始化为pj初始化为p + 1i的含义: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]

sfdl1.jpeg

sfdl2.jpeg

sfdl3.jpeg

sfdl4.jpeg

再来看看官方题解里快排的写法

为什么往左递归是(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 1.jpeg

2.jpeg

3.jpeg

4.jpeg

5.jpeg

6.jpeg

7.jpeg

8.jpeg

9.jpeg

10.jpeg

11.jpeg

12.jpeg

13.jpeg

14.jpeg

15.jpeg