如何解决此Stack Overflow错误?

时间:2016-03-30 00:53:20

标签: java recursion stack-overflow

任何时候我尝试在超过250个点测试此代码时会导致堆栈溢出错误,任何250和以下的代码都能正常工作。任何想法如何让它与更大的数字一起工作?

public class Divide {

    Point2D closest1;
    Point2D closest2;
    double Distance = Double.MAX_VALUE;
    int CurrentPoint = 0; 
    int NextPoint = 0;


    public Divide(Point2D[] RandArray){
        SortArray s = new SortArray();

        //Sort the array using SortArray class
        RandArray = s.SortPointsX(RandArray);

        SplitAndConquer(RandArray);
    }

    /**
     * Recursively call itself to check the distance between the points
     * sent in as parameters.
     * @param a first point to be compared for distance.
     * @param b second point to be compared for distance.
     * @param s array of points that is being compared.
     * @return The distance of the closest pair.
     */
    private double ComparePoints(Point2D a, Point2D b, Point2D[] s){
                //Checks to make sure two points aren't the same
                if (a.getX() != b.getX() || a.getY() != b.getY()){
                    CheckDist(a, b);
                }

                // Increments the NextPoint if it's not the last point in the array
                // and recursively calls the next point to compare current to.
                if (b != s[s.length - 1]){
                    NextPoint++;
                    ComparePoints(s[CurrentPoint], s[NextPoint], s);
                }

                /* Sets the NextPoint to whatever the Current point is to prevent
                 * wasting comparisons between two points that have already been 
                 * checked. Also increments the current point, and recursively 
                 * calls the next point to compare it to.
                 */ 
                if (b == s[s.length - 1]){
                    if (a != s[s.length - 1]){
                    NextPoint = s.length - ((s.length - 1) - CurrentPoint);
                    CurrentPoint++;
                    ComparePoints(s[CurrentPoint], s[NextPoint], s);
                    }
                }

                //if the current point is the point at the end of the array it
                //counters and returns the distance, ending the recursive calls
                if (a == s[s.length - 1]){
                    CurrentPoint = 0;
                    NextPoint = 0;
                    return Distance;
                    }
            return Distance;

    }

    /**
     * Checks the distance between two points.
     * @param a first point to be compared for distance.
     * @param b second point to be compared for distance.
     */
    private void CheckDist(Point2D a, Point2D b) {
        //Checks the distance between two points
        if (Distance > a.distance(b)){  
            Distance = a.distance(b);

            //save the coordinates of the closest pair
            closest1 = new Point2D.Double(a.getX(), a.getY());
            closest2 = new Point2D.Double(b.getX(), b.getY());
        }
    }

    /**
     * Splits the array into two subsets and finds the closest pair among them.
     * @param RandArray the array to be divided and searched.
    */
    private void SplitAndConquer(Point2D[] RandArray){
        //median of the array used to split the list into subsets
        double median = RandArray[RandArray.length/2].getX();

        //count used for splitting the array into subsets
        int countS1 = 0;
        int countS2 = 0;

        //checks to see if the median is the point being sorted
        boolean exact = false;

        //Array to hold all points with x coordinate < median
        Point2D[] s1 = new Point2D[RandArray.length/2];

        //Array to hold all points with x coordinate > median
        Point2D[] s2 = new Point2D[RandArray.length/2];

        //Split the array comparing x coordinates and median
        for (int i = 0; i < RandArray.length; i++){

            if (RandArray[i].getX() < median){
                s1[countS1] = RandArray[i];
                countS1++;
            }
            else if (RandArray[i].getX() > median){
                s2[countS2] = RandArray[i];
                countS2++;
            }
            //alternates median value to ensure even subsets
            else if (RandArray[i].getX() == median && exact == false){
                s2[countS2] = RandArray[i];
                exact = true;
                countS2++;
            }
            else if (RandArray[i].getX() == median && exact == true) {
                s1[countS1] = RandArray[i];
                exact = false;
                countS2++;
            }
        }

        //Compares points if there are more than 2 points
        if (s1.length > 2){
            ComparePoints(s1[0], s1[1], s1);
            ComparePoints(s2[0], s2[0], s2);
            }else{
                System.out.println
                ("One of the subsets does not contain enough points!");
            }

        //Checks the points that lie on the median
        CheckMid(RandArray, Distance, median, CurrentPoint, NextPoint);

        //Prints the closest pair
        PrintClosest();
        }

    /**
     * Prints the closest pairs found using Divide and Conquer
     */
    private void PrintClosest() {
        System.out.println("The closest pair found using Divide "
                + "And Conquer is at ("
                + closest1.getX() + " " + closest1.getY() + "), and (" 
                + closest2.getX() + " " + closest2.getY() + ")");
        System.out.println("The distance between the pairs is: " + Distance);

    }

    /**
     * Checks the original array but only points located with the current 
     * distance from the median which was used to split for subsets.
     * @param randArray Original array full of sorted points.
     * @param d Current distance of the closest pair.
     * @param m The median used to partition the array.
     * @param current Current index of point being compared.
     * @param next Index of the next point to be compared to current.
     */
    private void CheckMid(Point2D[] randArray, double d, double m,
            int current, int next) {

        //temp array list to hold all the points within the median + distance
        ArrayList<Point2D.Double> temp = new ArrayList<Point2D.Double>();
        for(int i = 0; i < randArray.length; i++){
            if(randArray[i].getX() > (m - d) && 
                    randArray[i].getX() < (m + d)){
                temp.add((java.awt.geom.Point2D.Double) randArray[i]);
            }
        }

        //Creates a new array to hold the values in the array list
        Point2D[] MidArray = new Point2D[temp.size()];
        for(int i = 0; i < temp.size(); i++)
        {
            MidArray[i] = temp.get(i);
        }

        //Makes sure the array list has enough points to be compared
        if (MidArray.length >= 2){
            if (MidArray[0] != null && MidArray[1] != null){
            ComparePoints(MidArray[0], MidArray[1], MidArray);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

递归调用函数时,将为每次调用创建堆栈帧。这些堆栈帧将累积,直到您到达递归的底部并开始以相反的顺序评估函数时才会释放。

堆栈的内存量有限,所以在某些时候你会递归调用你的函数太多次并且堆栈内存耗尽,堆栈溢出。

您可以将解决方案转换为使用迭代实现而不是递归实现,或者可以增加堆栈上的内存量。

值得记住的是,如果你增加堆栈中的内存,在某些时候,如果你过于沉重,你可能会再遇到这个问题。