簡體   English   中英

Java Quicksort二次運行時行為

[英]Java Quicksort quadratic runtime behaviour

我試圖在Java中實現一個有效的排序算法。 出於這個原因,我還實現了quicksort並使用以下代碼:

public class Sorting {
    private static Random prng;

    private static Random getPrng() {
        if (prng == null) {
            prng = new Random();
        }
        return prng;
    }

    public static void sort(int[] array) {
        sortInternal(array, 0, array.length - 1);
    }

    public static void sortInternal(int[] array, int start, int end) {
        if (end - start < 50) {
            insertionSortInternal(array, start, end);
        } else {
            quickSortInternal(array, start, end);
        }
    }

    private static void insertionSortInternal(int[] array, int start, int end) {
        for (int i=start; i<end - 1; ++i) {
            for (int ptr=i; ptr>0 && array[ptr - 1] < array[ptr]; ptr--) {
                ArrayUtilities.swap(array, ptr, ptr - 1);
            }
        }
    }

    private static void quickSortInternal(int[] array, int start, int end) {
        int pivotPos = getPrng().nextInt(end - start);
        int pivot = array[start + pivotPos];
        ArrayUtilities.swap(array, start + pivotPos, end - 1);
        int left = start;
        int right = end - 2;
        while (left < right) {
            while (array[left] <= pivot && left < right) {
                ++left;
            }
            if (left == right) break;
            while (array[right] >= pivot && left < right) {
                right--;
            }
            if (left == right) break;
            ArrayUtilities.swap(array, left, right);
        }
        ArrayUtilities.swap(array, left, end - 1);
        sortInternal(array, start, left);
        sortInternal(array, left + 1, end);
    }
}

ArrayUtilities.swap只是交換數組中的兩個給定元素。 從這段代碼中,我期望O(n log(n))運行時行為。 但是,要排序的一些不同長度的數組給出了以下結果:

10000個元素:32ms

20000個元素:128ms

30000個元素:296ms

在每種情況下測試運行100次,然后計算運行時間的算術平均值。 但顯然,與預期的行為相反,運行時為O(n^2) 我的算法出了什么問題?

在插入排序實現中,您的數組將按降序排序,而在快速排序中,數組按升序排序。 所以替換(降序):

for (int ptr=i; ptr>0 && array[ptr - 1] < array[ptr]; ptr--)

for (int ptr=i; ptr>0 && array[ptr - 1] > array[ptr]; ptr--)

您的索引似乎也不正確。 嘗試替換:

sortInternal(array, 0, array.length - 1);

有:

sortInternal(array, 0, array.length);

並且在插入中首先排序循環,你不需要做end - 1 ,即使用:

for (int i=start; i<end; ++i)

最后,添加if (start >= end) return; 在快速排序方法的開頭。

正如@ljeabmreosn所提到的那樣,50有點太大了,我會選擇5到20之間的東西。

希望有所幫助!

對於長度小於50個元素的數組,使用“插入排序”進行“優化”的QuickSort似乎是一個問題。

想象一下,我有一個大小為65的數組,並且樞軸恰好是該數組的中位數。 如果我通過您的代碼運行數組,您的代碼將在數據透視表左側和右側的兩個32長度子陣列上使用Insertion Sort。 這將導致~O(2 *(n / 2)^ 2 + n)=〜(n ^ 2)的平均情況。 使用快速排序並實施第一個樞軸的樞軸揀選策略 ,時間平均情況為~O((n log(n))+ n)= ~O(n (log(n)+ 1))= ~O (N *的log(n))。 不要使用Insertion Sort,因為它僅在數組幾乎排序時使用。 如果您使用Insertion Sort只是因為排序的實際運行時間小數組可能比標准快速排序算法(深度遞歸)運行得更快,您可以始終使用比插入排序運行更快的非遞歸快速排序算法。

也許將“50”改為“20”並觀察結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM