1

解決済み: このコメントの最後に投稿されました。

このエラーが発生し続けますが、なぜ発生するのかについての説明が見つかりません。

Exception in thread "main" java.lang.StackOverflowError
at java.util.Random.nextDouble(Random.java:444)
at java.lang.Math.random(Math.java:716)
at assignment6quickSort.M6.qsAlgorithm(M6.java:50)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)

私は狂ったようにグーグルしてきましたが、誰も同じ問題を抱えていないようです。または、正しいことを検索するのはばかげています(まったく可能です)。

とにかく、一般的なクイックソートのピボット番号を見つけるために乱数を作成していますが、数時間前には何度か機能しましたが、今では毎回このエラーが発生します。

お願い、私はとてもイライラしています.ふふふ​​!私は何を間違っていますか?これはどのようにオーバーフローを引き起こす可能性がありますか?

これが私のコードです...

package assignment6quickSort;

import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;


public class M6 {

    static M6Comparator<Integer> comp = new M6Comparator<Integer>();
    static Integer[] array = new Integer[20];
    static ArrayList qsSorted = new ArrayList();

    public static void main (String[] args) {       

        for (int i = 0; i < array.length; i++) {
            array[i] = (int)(50 * Math.random());
        }

        for (int i: array) {
            System.out.print(i + ", ");
        }

        quickSort(array, comp);
        System.out.println("\n");

        for (Object i: qsSorted) {
            System.out.print(i + ", ");
        }

    }

    static <T> void quickSort(T[] a, Comparator<? super T> comp) {

        ArrayList<T> temp = new ArrayList<T>();
        for (int i = 0; i < a.length; i++) {
            temp.add(a[i]);
        }

        qsSorted = qsAlgorithm(temp, comp);
    }

    static <T> ArrayList<T> qsAlgorithm(ArrayList<T> a, Comparator<? super T> comp) {

        ArrayList<T> L = new ArrayList<T>();
        ArrayList<T> G = new ArrayList<T>();

        if (a.size() <= 1) 
            return a;
        int pivot = (int)Math.random() * a.size();
        T pivotValue = a.get(pivot);
        for (int i = 0; i < a.size(); i++) {
            if (comp.compare(a.get(i), pivotValue) == -1 || comp.compare(a.get(i), pivotValue) == 0) {
                L.add(a.get(i));
            } else {
                G.add(a.get(i));
            }
        }

        L = qsAlgorithm(L, comp);
        G = qsAlgorithm(G, comp);
        L.addAll(G);

        return L;

    }

}

さらに、ここに私のコンパレータがあります:

package assignment6quickSort;

import java.util.Comparator;

public class M6Comparator<E> implements Comparator<E> {

    public int compare(E original, E other) {

        return((Comparable<E>)original).compareTo(other);
    }

}

### 解決 ###

どうやら古典的な再帰的なオーバーフロー エラーです。助けてくれた@pstと@Marcinに感謝します!qsAlgorithm() メソッドのリビジョンは次のとおりです。

static <T> ArrayList<T> qsAlgorithm(ArrayList<T> a, Comparator<? super T> comp) {

        ArrayList<T> L = new ArrayList<T>();
        ArrayList<T> P = new ArrayList<T>();
        ArrayList<T> G = new ArrayList<T>();

        if (a.size() <= 1)
            return a;
        int pivot = (int)Math.random() * a.size();
        T pivotValue = a.get(pivot);
        for (int i = 0; i < a.size(); i++) {
            int v = comp.compare(a.get(i), pivotValue);
            if (v == -1) {
                L.add(a.get(i));
            } else if (v == 0) {
                P.add(a.get(i));
            } else {
                G.add(a.get(i));
            }
        }

        return concatenate(qsAlgorithm(L, comp), P, qsAlgorithm(G, comp));

    }

    static <T> ArrayList<T> concatenate(ArrayList<T> a, ArrayList<T> p, ArrayList<T> b) {

        a.addAll(p);
        a.addAll(b);

        return a;

    }
4

3 に答える 3

3

スタックがオーバーフローするまで、再帰呼び出しを何度も入力しています。問題は、メインの比較ループで、常にすべての要素を一時配列「L」に追加し、「G」には何も追加しないポイントに到達することです。したがって、再帰呼び出しは次のようになります。

L = qsAlgorithm(L, comp);

常にパラメータと同じ数の要素で作成されます:

ArrayList<T> a

したがって、49 行目で再帰を終了することはありません。

if (a.size() <= 1) 
    return a;

解決策は、一時配列に最後の 2 つの等しい要素がある場合に、追加の終了を作成することです。

編集:手早く汚い修正...これは決して効率的なコードではありません。「偶数」値に別の「E」コレクションを使用し、それらを最後に結果のリストに追加しました。

static <T> ArrayList<T> qsAlgorithm(ArrayList<T> a, Comparator<? super T> comp) {

    ArrayList<T> L = new ArrayList<T>();
    ArrayList<T> E = new ArrayList<T>();
    ArrayList<T> G = new ArrayList<T>();

    if (a.size() <= 1) 
        return a;
    int pivot = (int)Math.random() * a.size();
    T pivotValue = a.get(pivot);
    for (int i = 0; i < a.size(); i++) {
        int v = comp.compare(a.get(i), pivotValue);
        if (v == -1) {
            L.add(a.get(i));
        } else if (v == 0) {
            E.add(a.get(i));
        } else {
            G.add(a.get(i));
        }
    }

    L = qsAlgorithm(L, comp);
    G = qsAlgorithm(G, comp);
    L.addAll(E);
    L.addAll(G);

    return L;

}
于 2013-03-05T18:31:27.170 に答える
3

実際にスタックをオーバーフローさせるのはおそらく nextDouble 関数ではありません。たまたま、各再帰ステップで呼び出しているため、限界に達する関数である可能性があります。本当の問題は、再帰が深すぎることです (おそらく、再帰を停止する間違った基本的なケースです)。

a.sizeあなたのバリアントのようです。再帰のすべてaのステップで実際に減少することを確認してください。

于 2013-03-05T18:26:58.170 に答える
2

ランダムはスタック オーバーフローを引き起こす再帰を引き起こしているわけではありません が、ラクダの背中を壊したストローです

以前の 2 トンの干し草の俵1 :

at assignment6quickSort.M6.qsAlgorithm(M6.java:50)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)
at assignment6quickSort.M6.qsAlgorithm(M6.java:60)
..

1提示されたコードの問題は、ピボットが再帰サブ問題に含まれていることです。としてシーケンス[x,x]で両方の値が再帰的に選択される入力の場合を想像してください。常に終端 (0 要素) になりますが、終端 (2 要素) になることはありません。Lx <= xRL

ウィキペディアのクイックソートを参照し、疑似コードに注意してくださいconcatenate(quicksort('less'), 'pivot', quicksort('greater'))。すなわち、ピボット要素は副問題に含まれない。

于 2013-03-05T18:27:05.057 に答える