为什么我的快速排序以相反的顺序对数组进行排序?

时间:2016-05-03 17:57:53

标签: java arrays sorting quicksort

我正在尝试为一个字符串数组实现一个快速排序,但似乎它对数组进行了排序,但顺序相反,我想知道为什么会这样,我怎么能解决这个问题才能正常排序...这个是我的实施:

public class Main {

    public static void main(String[] args) {
        String[] list = {"a", "f", "c", "b"};
        quickSort(list, 0, list.length - 1);
        for (String s : list) {
            System.out.println(s);
        }
    }

    private static void quickSort(String[] list, int start, int end) {
        if (start < end) {
            int pIndex = partition(list, start, end);
            quickSort(list, start, pIndex - 1);
            quickSort(list, pIndex + 1, end);
        }
    }

    private static int partition(String[] list, int start, int end) {
        String pivot = list[end];

        int leftCounter = start;
        int rightCounter = end;

        while (leftCounter < rightCounter) {
            while (list[leftCounter].compareTo(pivot) <= 0 && leftCounter < end && rightCounter > leftCounter) {
                leftCounter++;
            }
            while (list[rightCounter].compareTo(pivot) >= 0 && rightCounter > start && rightCounter >= leftCounter) {
                rightCounter--;
            }
            if (leftCounter < rightCounter) {
                swap(list, leftCounter, rightCounter);
            }
        }
        swap(list, start, end);
        return end;
    }

    private static void swap(String[] list, int start, int end) {
        String aux = list[start];
        list[start] = list[end];
        list[end] = aux;
    }
}

2 个答案:

答案 0 :(得分:2)

问题中提供的实施让我感到困惑。这并不是说它不正确(或者,至少接近正确),但我觉得它很难读(这可能更重要)。我可能只是很慢,而且这种实现实际上非常直观,但我倾向于它实现比连贯更聪明。

通常,quicksort是一种递归算法,它将一组数据相对于一个数据块(小于,等于和大于)分成三个数据块,然后对不相等的二进制数进行排序(使用相同的算法),然后合并结果以形成排序数据集。在英语中,它应该如何运作非常直观。它没有理由在代码中保持不变。我总是打算编写你能理解的代码(然后根据需要使它变得更有效),而不是试图写出一些你无法理解的东西,然后当它没有&#时就会起作用。 39;工作。

下面是一个更详细的实现(对我来说,至少)在其操作中似乎更清晰。它也是非常低效的(它产生了六个不同的列表和数组,只是为了对一组数据进行排序)。我不为此道歉;我假设这个问题本质上是学术性的。如果您确实需要提高效率,那么这对用户来说是一种练习,但没有理由不能将其分解为直观的步骤,如下所示(它会为您节省费用)很头疼)。

public class QuickSortTest {
    private static String[] data = new String[] {"a", "b", "c", "f", "b", "e", "b"};

    public static void main(String[] args) {
        String[] sortedData = quickSort(data);
        for (String str : sortedData) {
            System.out.println(str);
        }
    }

    private static String[] quickSort(String[] data) {
        // Edge case: return just the data if there are 0 or 1 elements (already sorted)
        if (data.length <= 1) {
            return data;
        }

        // Initialize the return structure
        String[] sortedData = new String[data.length];

        // Choose the pivot (can be any value)
        String pivot = data[data.length - 1];

        // Initialize the bins
        ArrayList<String> lessThan = new ArrayList<String>();
        ArrayList<String> equalTo = new ArrayList<String>();
        ArrayList<String> greaterThan = new ArrayList<String>();

        // Place the data into bins (based on the pivot)
        for (String str : data) {
            int compareValue = str.compareTo(pivot);
            if (compareValue < 0) {
                lessThan.add(str);
            }
            else if (compareValue > 0) {
                greaterThan.add(str);
            }
            else {
                equalTo.add(str);
            }
        }

        // Sort the non-equal data
        String[] lessThanSorted = quickSort(lessThan.toArray(new String[0]));
        String[] greaterThanSorted = quickSort(greaterThan.toArray(new String[0]));

        // Merge the data
        int length = 0;
        for (String less : lessThanSorted) {
            sortedData[length++] = less;
        }
        for (String equal : equalTo) {
            sortedData[length++] = equal;
        }
        for (String greater : greaterThanSorted) {
            sortedData[length++] = greater;
        }

        return sortedData;
    }
}

顺便说一句,如果有人希望在实践中对数据进行排序,只需使用Collections.sort()

即可

答案 1 :(得分:2)

问题在于您的partition方法:

   private static int partition(String[] list, int start, int end) {
        String pivot = list[end];

        int leftCounter = start;
        int rightCounter = end;

        while (leftCounter < rightCounter) {
            while (list[leftCounter].compareTo(pivot) <= 0 && leftCounter < end && rightCounter > leftCounter) {
                leftCounter++;
            }
            while (list[rightCounter].compareTo(pivot) >= 0 && rightCounter > start && rightCounter >= leftCounter) {
                rightCounter--;
            }
            if (leftCounter < rightCounter) {
                swap(list, leftCounter, rightCounter);
            }
        }

到目前为止,这基本上是标准Hoare partition。在此循环结束时,您的列表将显示为[l1, l2, ..., lx, g1, g2, ..., gy, pivot],其中l1, l2, ..., lx小于或等于数据透视表,g1, g2, ..., gy大于或等于数据透视表。 leftCounter指向g1rightCounter指向lx。您需要确保枢轴分隔两组并返回正确的索引:

        swap(list, start, end);
        return end;
    }

这两行是您问题的根源。您需要swap(list, leftCounter, end)将枢轴移动到列表中的正确位置。现在,您的列表将显示为[l1, l2, ..., lx, pivot, g2, g3, ..., gy, g1]。您需要返回数据透视的索引,即leftCounter

至于为什么它按相反的顺序排序:你很幸运。在其他输入上尝试它,它并不总是按相反的顺序排序。

String[] list = { "a", "c", "a", "b","c","f","g","a","b" }
  

[a,g,b,a,f,c,c,b,a]