Anytime I try to test this code on more than 250 points it results in a stack overflow error, anything 250 and under works perfectly. Any ideas how to make it work with larger numbers?
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);
}
}
}
}
When you recursively call a function, you create a stack frame for each invocation. These stack frames will accumulate and are not released until you reach the bottom of the recursion and start evaluating the functions in reverse order.
The stack has a finite amount of memory, so at some point you will recursively call your function too many times and run out of memory on the stack, a stack overflow.
You can convert your solution to use an iterative implementation instead of a recursive implementation, or you can increase the amount of memory on the stack.
It's worth keeping in mind that if you increase the memory on the stack, at some point you may well run into this problem again if you recurse too deeply.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.