50

以下のクイックソートアルゴリズムを実装しました。オンラインで、O(log(n))のスペース要件があることを読みました。これはなぜですか?余分なデータ構造を作成していません。

私の再帰がスタック上の余分なスペースを使用するためですか? この場合、再帰的ではなく(反復的にするのではなく)少ないメモリでそれを行うことは可能ですか?

private static void quickSort (int[] array, int left, int right) {
    int index = partition(array, left, right);

    //Sort left half
    if (left < index - 1)
        quickSort(array, left, index - 1);

    //Sort right half
    if (index < right)
        quickSort(array, index , right);
}

private static int partition (int array[], int left, int right) {
    int pivot = array[(left + right) / 2]; //Pick pivot point
    while (left <= right) {
        //Find element on left that should be on right
        while (array[left] < pivot)
            left++;

        //Find element on right that should be on left
        while (array[right] > pivot)
            right--;

        //Swap elements and move left and right indices
        if (left <= right) {
            int temp = array[left];
            array[left] = array[right];
            array[right] = temp;
            left++;
            right--;
        }
    }
    return left;
}
4

6 に答える 6

61

正解です。余分なスペースは log(n) スタック フレームです。Quicksortのウィキペディアの記事から:

[...] O(log n) スペース (入力をカウントしない) を使用して完全な並べ替えを達成できる、より複雑なバージョンがあります (呼び出しスタックの場合)

クイックソートを反復的に実装することもできますが (再帰の代わりにループを使用するなど)、クイックソートには 1 つだけでなく2 つの再帰呼び出しがあるため、補助スタックを維持する必要があります。

最後に、他の回答が指摘しているように、 O(log(n)) はほとんどすべての実用的なアプリケーションで非常小さいです。データ構造のオーバーヘッドなどのすべての定数要因は、メモリ使用量に大きな影響を与えます。

于 2012-09-24T21:47:13.297 に答える
11

再帰呼び出しをなくすには、コードでスタック データ構造を使用する必要がありますが、それでもlog(n)スペースを占有します。

于 2012-09-24T21:54:57.747 に答える
9

ウィキペディアの記事をさらに読むと、スペースの複雑さに関するより徹底的な議論が見つかります。特に、彼らは次のように書いています。

インプレースで不安定なパーティショニングを使用するクイックソートは、再帰的な呼び出しを行う前に、一定の追加スペースのみを使用します。クイックソートは、ネストされた再帰呼び出しごとに一定量の情報を格納する必要があります。最良の場合は、最大でO(log n)のネストされた再帰呼び出しを行うため、O(log n)スペースを使用します。ただし、再帰呼び出しを制限するSedgewickのトリックがなければ、最悪の場合、クイックソートはO(n)のネストされた再帰呼び出しを行い、O(n)の補助スペースを必要とする可能性があります。

実際には、O(log n)メモリは何もありません。たとえば、10億intを並べ替える場合、それらを格納するには4 GBが必要ですが、スタックに必要なスタックフレームは約30、つまり40バイト、合計で約1200バイトです。

于 2012-09-24T22:00:59.690 に答える
2

はい、それはスタック フレームが原因です。はい、非常に巧妙なことを行うことで反復アルゴリズムに変換できる可能性があります (ただし、すぐには何も思いつきません)。しかし、なぜ?O(log(n)) スペースはほとんどありません。参考までに、Java で許可されている最大サイズの配列がある場合でも、それは 2^31 要素、つまり約 8 GB です。クイックソートには 31 個のスタック フレームが必要です。大体、1 フレームあたり 100 バイトでしょうか。したがって、合計 3 KB です。これは、実際の配列のメモリと比較して何もありません。

実際には、何かが O(log(n)) であるほとんどの場合、定数とほとんど同じです。

于 2012-09-24T21:55:16.697 に答える