簡體   English   中英

Quicksort算法導致堆棧溢出

[英]Quicksort Algorithm causing stack overflow

已解決:發表在此評論的末尾。

我不斷收到此錯誤,但找不到導致此錯誤的任何解釋。

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)

我一直在瘋狂搜索,似乎沒有人遇到同樣的問題,或者我愚蠢地尋找正確的東西(完全可能)。

無論如何,我正在創建隨機數以查找通用quickSort的樞軸數,幾個小時前它已經工作了幾次,但現在每次都出現此錯誤。

拜托,我好沮喪...呵呵! 我到底在做什么錯? 這怎么會導致溢出?

這是我的代碼...

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;

    }

可能不是nextDouble函數真正使堆棧溢出,恰恰是您在每個遞歸步驟中都在調用它,因此很可能是達到極限的函數。 真正的問題是遞歸的深度太深(也許是錯誤的基本情況,您可能停止遞歸)。

看起來a.size是您的變體 確保遞歸的一步確實減少a

您進入遞歸調用的次數太多了,直到堆棧溢出為止。 問題在於,您到達了主比較循環中的某個點,在該點上,您總是將所有元素添加到臨時數組“ L”,而沒有元素添加到“ G”,因此您進行了遞歸調用:

L = qsAlgorithm(L, comp);

總是使用與param相同數量的元素制成:

ArrayList<T> a

因此,您永遠不會在第49行中退出遞歸:

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

解決方案是當您的臨時數組具有最后兩個相等元素時再退出。

編輯:快速而骯臟的修復...這絕對不是高效的代碼。 我為“偶數”值使用了另一個“ 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;

}

隨機不會導致導致堆棧溢出的遞歸,但它 壓垮駱駝的最后一根稻草

先前的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]的情況,其中兩個值在L序列中遞歸選擇為x <= x R將始終是終端(0個元素),但L永遠不會是終端(2個元素)。

請參閱Wikipedia上的Quicksort,並注意偽代碼concatenate(quicksort('less'), 'pivot', quicksort('greater')) 即,樞軸元素不包括在子問題中。

暫無
暫無

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

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