簡體   English   中英

使用Quicksort和中值實現的堆棧溢出錯誤

[英]Stack overflow error with Quicksort and median implementation

首先,我要說明這是一個家庭作業問題,我已經做了大量的嘗試。

我被要求修改Java中的quicksort以使用公式i * (n-1) /8將數據庫設置為數組中9個值的偽中位數

我寫了一個computeMedian方法,它接受3個整數,確定最高值,然后返回該值。

編碼:

public static int computeMedian(int x, int y, int z)
    {
        if((x >= y && x <= z) || (x >= z && x <= y)) {return x;}
        else if((y >= x && y <= z) || (y >= z && y <= x)) {return y;}
        else if((z >= x && z <= y) || (z >= y && z <= x)) {return z;}
        else { return 0; }
    }

然后我在findPivot方法中使用它,它將當前array, from, to取值array, from, to值並使用它們來構造一個數據透視表

這是代碼:

public static int findPivot(int[] a, int from, int to)
    {
        if(a.length <= 7)
        {
            return a[(to)/2];
        }
        else if(a.length > 7 && a.length <= 40)
        {
            return computeMedian(a[from], a[(to)/2] , a[to]);
        }
        else
        {
            int x = computeMedian(a[0 * (to) / 8], a[1 * (to) / 8], a[2 * (to) / 8]);
            int y = computeMedian(a[3 * (to) / 8], a[4 * (to) / 8], a[5 * (to) / 8]);
            int z = computeMedian(a[6 * (to) / 8], a[7 * (to) / 8], a[8 * (to) / 8]);
            return computeMedian(x,y,z);
        }
    }

這個方法適用於排序小於或等於40的任何數組,但是一旦它大於40,我就會收到堆棧溢出錯誤,導致返回到else {}部分的computeMedian方法。 我會注意到return computeMedian(a[from], a[(to)/2] , a[to]); 如果我把它放在那里,則工作在> 40部分,但這只是3個值的中位數,而不是3個中位數的中位數。

目前這就是我將findPivot插入到findPivot分區方法中的方法:

private static int modPartition(int[] a, int from, int to)
    {
        int pivot = findPivot(a, from, to);
        int i = from - 1;
        int j = to + 1;
        while(i < j)
        {
            i++; while (a[i] < pivot) { i++; }
            j--; while (a[j] > pivot) { j--; }
            if (i < j) { swap(a, i, j); }
        }
        return j;
    }

我很難理解為什么我的computeMedian方法無法在更大的數據集上工作。 我嘗試通過for循環將i * (n-1) / 8值放在數組中,對它們進行排序並在中間返回值,並將值放在數組p並調用computeMedian(computeMedian(p[0], p[1], p[2]), computeMedian(p[3],p[4],p[5]),...etc我得到相同的堆棧溢出問題,但它往往會移動我的代碼的不同部分,並引導我的圈子。

如果有人需要,我可以發布任何更多的片段,但我認為我的問題可能就在這里。

謝謝您的幫助。 我還在學習,我認為抓住這個將完全幫助我在將來自己解決問題。

以下是堆棧跟蹤中的問題行:第16行: int p = modPartition(a, from, to); 第18行modSort(a, p+1, to); 第23行int pivot = findPivot(a, from, to);

繼承了我的整個modSort方法:

public static void modSort(int[]a, int from, int to)
    {
        if(from >= to) { return; }
        int p = modPartition(a, from, to);
        modSort(a, from, p);
        modSort(a, p+1, to);
    }

轉載並更正

添加代碼以重現錯誤...

private static void swap(int[] a, int i, int j) {
    int tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;
}

public static void main(String[] args) {
    // Generate a sample
//      ArrayList<Integer> list = new ArrayList<>(64);
//      for (int i = 0; i < 64; i++) list.add(i);
//      Collections.shuffle(list);
//      System.out.println(list);
    int[] arr = {40, 9, 2, 62, 8, 42, 46, 23, 61, 45, 63, 48, 43, 36, 33, 32, 1, 55, 7, 17, 16, 25, 5, 26, 22, 11, 56, 38, 60, 31, 58, 29, 51, 34, 24, 54, 4, 3, 30, 20, 57, 18, 50, 44, 41, 12, 59, 6, 53, 39, 37, 35, 28, 13, 14, 15, 0, 19, 49, 52, 21, 27, 47, 10};

    modSort(arr, 0, arr.length-1);

    System.out.println(Arrays.toString(arr));
}

調試。 StackOverFlowError設置斷點(如注釋中所示)不起作用。 所以我去了一個常規斷點( modSort )。

對於此示例,數據開始對modSort進行無限遞歸,其中from=3;to=5 對於該范圍,樞軸p = 2,這似乎是異常的。

我責備findPivot(a,from,to)方法。 看起來很適合找到整個a的樞軸,但不適用於范圍。 嘗試此更正:

public static int findPivot(int[] a, int from, int to) {
    final int rangeLength = to - from + 1;
    if(rangeLength <= 7) {
        return a[(from + to)/2];
    } else if(rangeLength  <= 40) { // why test "a.length > 7" ?
        return computeMedian(a[from], a[(from + to)/2] , a[to]);
    } else {
        final int rangeLength_8 = (to - from) / 8;
        int x = computeMedian(a[from], a[from + rangeLength_8], a[from + 2 * rangeLength_8]);
        int y = computeMedian(a[from + 3 * rangeLength_8], a[from + 4 * rangeLength_8], a[from + 5 * rangeLength_8]);
        int z = computeMedian(a[from + 6 * rangeLength_8], a[from + 7 * rangeLength_8], a[to]);
        return computeMedian(x,y,z);
    }
}

然后它適用於我的例子。 我此時就停止了(必須要睡一覺)。

我認為你應該嘗試熟悉調試器。 我認為應該更容易弄明白。

既然您實際上已經包含了堆棧溢出問題的代碼和錯誤消息,我們可以幫助您。

從堆棧跟蹤中,我們可以看到無限遞歸可能是對modSort的第二次調用,因為第18行是重復的。

由於該調用與傳入參數之間的唯一區別是第二個參數,因此我認為p上的錢少於from

確認這是插入一個很好的老式print聲明的最佳方法。

public static void modSort(int[]a, int from, int to)
{
    if(from >= to) { return; }
    int p = modPartition(a, from, to);
    System.out.println("from=" + from + ", to=" + to + ", p=" + p);
    modSort(a, from, p);
    modSort(a, p+1, to);
}

結果輸出應該顯示出錯誤的非常明確的模式。

暫無
暫無

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

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