为什么我的java程序显示StackOverflowError?

时间:2018-04-23 20:24:21

标签: java sorting

我编写了一个基于quicksort原理对数组元素进行排序的程序。所以程序所做的是它接受一个数组,假设第一个元素作为数据,然后将它与数组的其余元素进行比较。如果元素发现更大,那么它将存储在另一个相同数组的最后(例如b),如果元素小于小于它将该元素放在数组b的开头。通过这种方式,枢轴将找到通向阵列中间的路径,其中左侧的元素较小,而右侧的元素大于枢轴。然后将数组b的元素复制到主数组,并通过递归调用整个函数。这是必需的代码。

package sorting;
import java.util.*;
public class AshishSort_Splitting {
    private static Scanner dogra;
    public static void main(String[] args)
    {
        dogra=new Scanner(System.in);
        System.out.print("Enter the number of elements ");
        int n=dogra.nextInt();
        int[] a=new int[n];
        for(int i=n-1;i>=0;i--)
        {
            a[i]=i;
        }
        int start=0;
        int end=n-1;
        ashishSort(a,start,end);
        for(int i=0;i<n;i++)
        {
            System.out.print(+a[i]+"\n");
        }
    }
    static void ashishSort(int[]a,int start,int end)
    {
        int p;
        if(start<end)
        {
            p=ashishPartion(a,start,end);
            ashishSort(a,start,p-1);
            ashishSort(a,p+1,end);
        }
    }
    public static int ashishPartion(int[] a,int start,int end)
    {
        int n=start+end+1;
        int[] b=new int[n];
        int j=start;
        int k=end;
        int equal=a[start];
        for(int i=start+1;i<=end;i++)
        {
            if(a[i]<equal)
            {
                b[j]=a[i];
                j++;
            }
            else if(a[i]>equal)
            {
                b[k]=a[i];
                k--;
            }
        }
        b[j]=equal;
        for(int l=0;l<=end;l++)
        {
            a[l]=b[l];
        }
        return j;
    }
}

当我输入n到13930的值时,此代码工作正常,但在此之后,它显示

Exception in thread "main" java.lang.StackOverflowError
    at sorting.AshishSort_Splitting.ashishSort(AshishSort_Splitting.java:28)
    at sorting.AshishSort_Splitting.ashishSort(AshishSort_Splitting.java:29)

我知道由于错误的递归导致的错误,但我多次测试我的代码并且没有找到更好的替代方案。请帮忙。提前谢谢。

编辑:有人可以建议一种方法来克服这个问题。

1 个答案:

答案 0 :(得分:0)

我首先看到了性能问题。我在你的分区方法中看到了:

int n = start+end+1

就在那里,如果在int [1000]上使用start = 900和end = 999调用该方法,那么你正在分配一个int [1900] ......不打算,我认为......!

如果您真的要丢弃内存而不是就地分区, 假设

int n = end-start+1

而不是更小的分配,j和k索引b [],它们将是j = 0和k = n,并返回start + j。

第二,你的

else if(a[i]<equal)

不是必需的并导致错误。一个简单的其他就足够了。如果您不替换b [j..k]中的0,则在重新填充[]时会遇到麻烦。

最后,你的最终副本是假的,从[0到end]超出了调用的范围[start..end],最重要的是,你的b中[b附近0]通常没有任何兴趣[]原样。 b []的区域(在您的版本中)是[start..end](在我建议的版本中它将是[0..n-1])

这是我的版本,但它仍然存在评论中提到的O(n)堆栈问题。

public static int ashishPartion(int[] a, int start, int end) {
    int n = end-start + 1;
    int[] b = new int[n];
    int bj = 0;
    int bk = n-1;
    int pivot = a[start];
    for (int i = start + 1; i <= end; i++) {
        if (a[i] < pivot) {
            b[bj++] = a[i];
        } else {
            b[bk--] = a[i];
        }
    }
    b[bj] = pivot;
    System.arraycopy(b, 0, a, start, n);
    return start+bj;
}

如果您可以自由选择排序算法,那么mergesort在性能上会更均匀,具有logN堆栈深度。易于实施。

否则,你将不得不使用手动堆栈来解除你的算法,这是一个很好的功课,我不会为你做的...... LOL