快速排序3路Partitiion

时间:2017-08-20 13:49:35

标签: algorithm sorting quicksort

我尝试使用3路分区技术实现快速排序算法,使用" m1"和" m2"作为索引来分隔元素等于枢轴的区域。 这是我的代码:

public class Sorting {
private static Random random = new Random();

private static int[] partition3(long[] a, int l, int r) {
    long x = a[l];
    int m1 = l;
    int m2 = l;

    for (int i = l + 1; i <= r; i++) {
        if (a[i] < x) {
            m1++;
            m2++;
            swap(a, m1, m2);

        }

        if (a[i] == x) {
            m2++;
            swap(a, i, m1);
        }
    }
    swap(a, l, m1);


    int[] m = {m1, m2};
    return m;
}

private static void swap(long[] a, int i, int j) {
    long temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

private static void randomizedQuickSort(long[] a, int l, int r) {
    if (l >= r) {
        return;
    }
    int k = random.nextInt(r - l + 1) + l;
    long t = a[l];
    a[l] = a[k];
    a[k] = t;
    int m[] = partition3(a, l, r);
    randomizedQuickSort(a, l, m[0] - 1);
    randomizedQuickSort(a, m[1] + 1, r);
}

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    int n = scanner.nextInt();
    long[] a = new long[n];
    for (int i = 0; i < n; i++) {
        a[i] = scanner.nextLong();
    }
    randomizedQuickSort(a, 0, n - 1);
    for (int i = 0; i < n; i++) {
        System.out.print(a[i] + " ");
    }
}

}

大多数情况下,它会为我的测试输出正确的答案,但有时并没有。谁能告诉我我做错了什么?

2 个答案:

答案 0 :(得分:0)

当您在列表中重复数字时,您的代码会失败。例如,您的代码未通过测试用例:

  

1 2 1 3 1

由于随机数生成,它每次都会返回不同的内容,但它不会成为正确的答案。这是您的partition3()函数的问题,特别是for循环中的情况,您可以在其中决定增量和翻转的位置。在这种情况下:

if (a[i] < x) {
    m1++;
    m2++;
    swap(a, m1, m2);
}

您错过了将第i个索引移动到正确位置的交换。交换看起来像这样:

if (a[i] < x) {
    m1++;
    m2++;
    swap(a, m1, m2);
    swap(a, m1, i); //The missing swap.
}

在你的其他条件中,你错过了两件事。首先,它应该是一个else-if,以避免意外进入两个if条件。其次,你在错误的位置交换。您应该在m2(第二个墙)处交换,而不是在m1处交换。这是因为第二个墙处理与枢轴相同的值,而不是第一个。更正了,你的第二个if条件看起来是这样的:

else if (a[i] == x) { //Note the addition of the else
    m2++;
    swap(a, i, m2); //Corrected, now swaps at m2
}

通过这些更正,您的代码似乎可以按预期工作。

答案 1 :(得分:0)

如果&#34; m1&#34;它会更容易和&#34; m2&#34; (等于&#39;区域的两个分隔符)从相对的边开始。如果元素小于数据透视表,则使用左边界定符进行交换,如果大于数据透视表,则使用右边界定符进行交换。否则,如果它相等,我们只需移动&#34; i&#34;指数。它会是这样的:

 private static int[] partition3(long[] a, int l, int r) {
     long x = a[l];
     int m1 = l;
     int m2 = r;

     int i = l + 1;

     while(i <= m2) {
         if (a[i] > x) {
             swap(a, i, m2);
             m2--;
         } else if (a[i] < x) {
             swap(a, m1, i);
              m1++;
             i++;
         } else {
             i++;
         }
     }

     int[] m = {m1, m2};
     return m;
 }