StackOverFlowError w / Recursive Sort

时间:2014-02-20 03:10:00

标签: java sorting recursion

当我尝试在长度大于50的数组上使用递归排序时,我得到一个StackOverFlowError。如果数组足够小,不会抛出此错误,该方法会正确排序。有没有办法解决这个问题?

public class RecursiveSort
{
    static double[] arr;
    static int count = 0;
    public static void main(String[] args)
    {
        double[] anArr = new double[50];

        for(int i = 0; i < anArr.length; i++) {

            anArr[i] = Math.random();

        }



        arr = anArr;
        recurseSort(arr.length - 1);
        display();
    }

    public static void recurseSort(int position)
    {

        if(position == 0)
        {
            position = arr.length - 1;
            count++;
        }
        if (arr[position] < arr[position - 1])
        {
            double n = arr[position - 1];
            arr[position - 1] = arr[position];
            arr[position] = n;
        }

        if(count <= arr.length)
            recurseSort(--position);

    }

    public static void display()
    {
        for(double n : arr)
            System.out.println(n);
    }

}

3 个答案:

答案 0 :(得分:1)

您的递归是尾递归,因此您可以将其替换为do-while

public static void recurseSort(int position)
    {

      do{

        if(position <= 0)
        {
            position = arr.length - 1;
            count++;
        }
        if (arr[position] < arr[position - 1])
        {
            double n = arr[position - 1];
            arr[position - 1] = arr[position];
            arr[position] = n;
        }


       position--;

       }while(count <= arr.length); //end while

    }

答案 1 :(得分:0)

首先,您似乎实现了某种bubble sort。我从未尝试使用递归,并且没有看到这样做的任何意义,因为实现此算法通常是直接的并且由两个嵌套循环组成,其内部有条件地交换相邻的列表元素。我没有看到任何递归方法......

毫不奇怪,你在那里做的并不是真正的递归,因为你只对常量维度的静态类成员(arrcount)进行操作。然而,排序算法中递归的优点在于每个递归步骤中相应参数复杂度的降低;通过使用一个方法,在将所述列表拆分为两个之后,将未排序的列表作为参数调用自身两次,每次调用该方法时,对这两个子集中的每一个进行排序变得更加容易。这样的方法可能看起来像这样:

private static double[] sort(double[] arr) {
  int splt = arr.length >> 2;
  // terminate if sorting is trivial
  if (splt < 3) {
    if (splt < 2) return arr;
    if (arr[0] > arr[1]) {
      return new double[2]{arr[1], arr[0]};
    } else return arr;
  }
  // split array and sort separately
  double[] left = new double[splt];
  double[] rght = new double[arr.length-splt];
  System.arraycopy(arr, 0, left, 0, splt);
  System.arraycopy(arr, splt, rght, 0, rght.length);
  return mergeArraysSomehow(sort(left), sort(right));
}

适当的除法可以将递归深度限制为log(n),其中n是数组长度。你正在做的是当它实际上只是继续循环时继续进行方法调用。每次recurseSort调用自身时,其字节码,参数和私有变量都会被复制到堆栈中,而不会返回任何调用,从而释放堆栈内存!只有当堆栈持有n的{​​{1}} 2 调用时,方法调用才能开始返回。值recurseSort的{​​{1}}就足够了[因为被平方]来填充并超过整个堆栈大小。

如果必须以递归方式执行此操作,请至少在n不再需要交换元素时停止递归。或者忘记冒泡排序并实现快速排序或合并排序。

答案 2 :(得分:0)

问题在于递归基于定义两个步骤,一个停止步骤(或基本情况)和一个递归步骤。在后者中,您需要使用递归调用解决整个问题,但问题较小。例如,乘法可以通过将乘数指示的相同数量相加多次来实现(4乘5表示将4加总为5的次数)。如果以递归方式执行,则为:

int multiply(int n, int multiplier)
{
    // Stopping step or base case
    if (multiplier == 1) return n;

    // Recursion step: Solving the whole problem using a recursion call
    return n + multiply(n, multiplier - 1);

}

在你的程序中你有基本情况,但在递归步骤中你没有解决整个问题。如果它们应该被交换,你可以交换arr [position]和arr [position-1],但这并不能保证递归调用中的整个子数组都会被排序。如果解决了整个问题,就可以解决递归问题。这就是为什么快速排序算法(和其他人)分裂数组选择一个元素,并将每个小于此的其他元素放在其左侧,并且每个其他更大的元素,最后,递归地调用自身以对两个半部分进行排序。阵列。

当然,这是J. Katzwinkel所描述的问题。