Quicksort实现:使用随机数据时几乎排序

时间:2016-03-26 21:56:14

标签: java arrays sorting quicksort

我正在努力实施quicksort作为一些练习和自我审查。目前,这只是一个原始整数数组的简单实现。在让这个工作正常之后,我计划将其设为通用。

我在下面的内容中仍然有一个小小的错误,我无法追踪到。我最初编写它只是使用左索引作为枢轴,一切正常。然而,一旦我完成了它的编写并将其切换为使用随机支点,事情就不再适合了。我的测试数组变得几乎排序,但是一些元素仍然是它们应该存在的两到三个索引。

以下是我的一些测试用例,它们在执行此操作时表现出不正确的行为:

6, 5, 1, 3, 8, 4, 7, 9, 2

1, 2, 3, 4, 5

5, 4, 3, 2, 1

 /**
 * Sort an integer array using quicksort
 * 
 * @param a Array to sort
 */
public static void quicksort(int[] a) {
    partition(0, a.length - 1, a);
}

/**
 * Partition a section of an integer array around a randomly selected pivot within that section
 *
 * @param left Lower-bound index of section (inclusive)
 * @param right Upper-bound index of section (inclusive)
 * @param a Array to perform partitioning within
 */
private static void partition(int left, int right, int[] a) {
    // Exit if partition is only a single element
    if (right - left < 1) { return; }

    // Select a pivot at random
    int pivot = ThreadLocalRandom.current().nextInt(left, right + 1);

    // Move pivot to left-most position (get out of the way)
    swap(left, pivot, a);

    // Perform partitioning
    int cur = left + 1;
    for (int i = left + 1; i <= right; i++) {
        if (a[i] < a[pivot]) {
            swap(i, cur, a);
            cur++;
        }
    }

    // Put pivot back where it belongs
    swap(left, cur - 1, a);

    // Partition the two new partitions
    partition(left, cur - 2, a);
    partition(cur, right, a);
}

/**
 * Swaps two elements in an array of integers
 *
 * @param i Index of first element to swap
 * @param j Index of second element to swap
 * @param a Integer array to perform swap on
 */
private static void swap(int i, int j, int[] a) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

2 个答案:

答案 0 :(得分:1)

将我的评论转换为答案:

在代码的这一部分中,您将使用最左边的元素交换pivot元素:

// Select a pivot at random
int pivot = ThreadLocalRandom.current().nextInt(left, right + 1);

// Move pivot to left-most position (get out of the way)
swap(left, pivot, a);

但是,您实际上并未更改pivot元素的索引。这意味着在这个分区逻辑中,你正在查看数组中的错误索引:

for (int i = left + 1; i <= right; i++) {
    if (a[i] < a[pivot]) {
        swap(i, cur, a);
        cur++;
    }
}

答案 1 :(得分:0)

好的,尝试使用left而不是pivot。它将颠倒列表的种类。

if (a[i] > a[left]) {
            swap(i, cur, a);
            cur++;
}

您没有考虑更改。

我更习惯使用右侧的枢轴。我保持你的实施很小。我的问题是,首先必须是&gt;左边和快速分区(左,cur-1,a)可能是必要的。

交换位置也应该已经排序。您可以通过基于正确的方法对此进行说明。

partition(left, cur -1 , a);
partition(cur + 1, right, a);

您可以在Wikipedia

了解实施情况

我的代码在编码地运行。

public class HelloWorld{

   int[] a = null;



    /**
 * Sort an integer array using quicksort
 * 
 * @param a Array to sort
 */
public void quicksort() {
    partition(0, a.length - 1, a);
}

/**
 * Partition a section of an integer array around a randomly selected pivot within that section
 *
 * @param left Lower-bound index of section (inclusive)
 * @param right Upper-bound index of section (inclusive)
 * @param a Array to perform partitioning within
 */
private  void partition(int left, int right, int[] a) {
    // Exit if partition is only a single element
    if (right <= left || right - left == 0) { return; }

    // Select a pivot at random
    int pivot =  left + new java.util.Random().nextInt(right - left);
    pivot = right;

    // Move pivot to left-most position (get out of the way)
    swap(right, pivot, a);

    // Perform partitioning
    int cur = left;
    for (int i = left; i < right; i++) {
        if (a[i] <= a[right]) {
            swap(i, cur, a);
            cur++;
        }
    }

    // Put pivot back where it belongs
    swap(cur, right , a);

    // Partition the two new partitions
    partition(left, cur -1 , a);
    partition(cur + 1, right, a);
}

/**
 * Swaps two elements in an array of integers
 *
 * @param i Index of first element to swap
 * @param j Index of second element to swap
 * @param a Integer array to perform swap on
 */
private void swap(int i, int j, int[] a) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}


     public static void main(String []args){
         int[] arr = new int[]{0,4,2,3,9,11,20,100,50,32,45,27,13,2,1,4,99,1,4};
         HelloWorld hw = new HelloWorld();
         hw.a = arr;
         hw.quicksort();
         for(int i = 0;i< arr.length;i++){
             System.out.println(arr[i]);
         }
     }
}

以下是带左侧枢轴的代码。

public class HelloWorld{

   int[] a = null;



    /**
 * Sort an integer array using quicksort
 * 
 * @param a Array to sort
 */
public void quicksort() {
    partition(0, a.length - 1, a);
}

/**
 * Partition a section of an integer array around a randomly selected pivot within that section
 *
 * @param left Lower-bound index of section (inclusive)
 * @param right Upper-bound index of section (inclusive)
 * @param a Array to perform partitioning within
 */
private  void partition(int left, int right, int[] a) {
    // Exit if partition is only a single element
    if (right <= left || right - left == 0) { return; }

    // Select a pivot at random
    int pivot =  left + new java.util.Random().nextInt(right - left);


    // Move pivot to left-most position (get out of the way)
    swap(left, pivot, a);

    // Perform partitioning
    int cur = left + 1;
    for (int i = left +1 ; i <=  right; i++) {
        if (a[i] < a[left]) {
            swap(i, cur, a);
            cur++;
        }
    }


    // Put pivot back where it belongs
    swap(cur - 1 , left , a);

    // Partition the two new partitions
    partition(left, cur - 2 , a);
    partition(cur , right, a);
}

/**
 * Swaps two elements in an array of integers
 *
 * @param i Index of first element to swap
 * @param j Index of second element to swap
 * @param a Integer array to perform swap on
 */
private void swap(int i, int j, int[] a) {
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}


     public static void main(String []args){
         int[] arr = new int[]{6, 5, 1, 3, 8, 4, 7, 9, 2};
         HelloWorld hw = new HelloWorld();
         hw.a = arr;
         hw.quicksort();
         for(int i = 0;i< arr.length;i++){
             System.out.println(arr[i]);
         }
     }
}