1

我最近尝试使用 C++ 实现最近对算法,我的大部分代码都受到了我在 GeeksforGeeks 上发现的启发。但是,我似乎无法运行具有较大 n 值的代码。我之前尝试输入 5,000,000 作为 n 值,然后进程在几秒钟后终止,没有显示任何输出。我需要能够达到至少 n = 5,000,000。现在,我的程序似乎停留在 n = 100,000 左右。它确实可以生成直到 n = 250,000 的随机数,但它会在进行最接近的配对计算之前终止。

这是我的代码。我真的更喜欢使用数组来收集值,但如果不可能,请赐教(我应该使用向量还是其他任何东西)。

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <random>
using namespace std;

//declares a class for a point with coordinates (x and y)
class Point
{
public:
    unsigned long int x,y;
};

class Result
{
public:
    Point a,b;
    long double d;
};

//utility void function to swap values in an array to assist with the sorting functions
void swaps(Point *a, Point *b)
{
    Point temp;
    temp.x = a->x;
    temp.y = a->y;
    a->x = b->x;
    a->y = b->y;
    b->x = temp.x;
    b->y = temp.y;
}

unsigned long int partition (Point arr[], unsigned long int low, unsigned long int high)
{
    unsigned long int pivot = arr[high].x; //set pivot as the x value of the last element in the array
    unsigned long int i = (low - 1); //the index of the smaller element

    for (unsigned long int j = low; j <= high - 1; j++)
        //swap current element if it is smaller than pivot
        if (arr[j].x < pivot)
        {
            i++; //increment index of smaller element
            swaps(&arr[i], &arr[j]);
        }
    swaps(&arr[i + 1], &arr[high]);
    return (i + 1);
}

//void function to sort the Point array P according to the x values of its elements
void xsort(Point arr[], unsigned long int low, unsigned long int high)
{
    if (low < high)
    {
        unsigned long int pi = partition(arr, low, high);

        xsort(arr, low, pi - 1);
        xsort(arr, pi + 1, high);
    }
}

//function to calculate distance between 2 points
long double dist(Point p1, Point p2)
{
    return (sqrt((p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y)));
}

//brute force function to find the closest distance between points by one-to-one comparing
Result bruteForce(Point P[], unsigned long int n)
{
    Result tempresult;
    tempresult.d = dist(P[0], P[1]);
    tempresult.a = P[0];
    tempresult.b = P[1];
    for (unsigned long int i=0; i<n; i++)
    {
        for (unsigned long int j=i+1; j<n; j++)
            if (dist(P[i], P[j]) < tempresult.d)
                {
                tempresult.d = dist(P[i], P[j]);
                tempresult.a = P[i];
                tempresult.b = P[j];
                }
    };
    return tempresult;
}

//function to return the minimum value between 2 values entered
long double min(long double v1, long double v2)
{
    if (v1<=v2) return v1;
    else return v2;
}

//function to calculate the minimum distance between points across midpoint borders
Result crossFunction(Point P[], unsigned long int n, Result tempresult)
{
    for (unsigned long int i=0; i<n; ++i)
        for (unsigned long int j = i+1; j < n && (P[j].x - P[i].x) < tempresult.d; j++)
            if (dist(P[i],P[j]) < tempresult.d)
                {
                tempresult.d = dist(P[i], P[j]);
                tempresult.a = P[i];
                tempresult.b = P[j];
                }
    return tempresult;
}

//function that includes the critical code of divide-and-conquer to solve the problem
Result closestUtil(Point P[], unsigned long int n)
{
    if (n<=3)
        return bruteForce(P, n);

    Result tempresult, crossresult, finalresult;

    //determine the middle point of the array
    unsigned long int mid = n/2;
    Point midPoint = P[mid];

    //breaks the array recursively until it reaches n<=3
    Result half1 = closestUtil(P, mid);
    Result half2 = closestUtil(P + mid, n - mid);

    //compares the two closest distances found in both halves and find the minimum of both
    tempresult.d = min(half1.d, half2.d);
    if (tempresult.d == half1.d)
    {
        tempresult.a = half1.a;
        tempresult.b = half1.b;
    }
    else
    {
        tempresult.a = half2.a;
        tempresult.b = half2.b;
    }

    //creates an array to store all points closer to the midpoint than the current local closest value
    Point cross[n];
    unsigned long int j=0;
    for (unsigned long int i=0; i<n-1; i++)
        if (abs(dist(P[i], midPoint)) < tempresult.d)
        {
         cross[j] = P[i];
         j++;
        }

    crossresult = crossFunction(cross, j, tempresult);

    finalresult.d = min(tempresult.d, crossresult.d);

    if (finalresult.d == tempresult.d)
    {
        finalresult.a = tempresult.a;
        finalresult.b = tempresult.b;
    }
    else
    {
        finalresult.a = crossresult.a;
        finalresult.b = crossresult.b;
    }
    return finalresult;
}

Result closestPair(Point P[], unsigned long int n)
{
    xsort(P,0,n-1);
    return closestUtil(P,n);
};

int main()
{
    unsigned long int n, x, y;
    cout << "Enter the number of points: "; cin >> n;
    cout << "Enter grid size (x y): "; cin >> x >> y;
    Point P[n];
    Result closest;
    srand((unsigned)time(NULL));
    for(long int i=0; i<n; i++)
    {
        P[i].x=rand()%x+1;
        P[i].y=rand()%y+1;
    }
    cout << "\nPOINT \t\t X \t Y " << endl << "----------------------------------" << endl;
    for (unsigned long int i=0; i<n; i++)
        cout << i+1 << "\t|\t" << P[i].x << "\t" << P[i].y << "\n";

    closest = closestPair(P,n);

    cout << endl << "The closest distance between points is " << closest.d << " and it is found "
    << "between point (" << closest.a.x << ", " << closest.a.y << ") and point (" << closest.b.x << ", "
    << closest.b.y << ").";

    return 0;
}

更新:感谢您的建议!我修复了我的代码并使用了向量。它工作得很好。但是,当我尝试在大 n 值上使用大边框进行点随机化时,有时它们会显示非常不准确的结果。它只会计算点的 x 坐标之间的距离,而不是考虑 y 坐标。这是我修改后的代码。我想知道错误可能在哪里。提前致谢!

#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <random>
using namespace std;

//declares a class for a point with coordinates (x and y)
struct Point
{
    unsigned long int x,y;
};

class Result
{
public:
    Point a,b;
    long double d;
};

bool compareX(Point a, Point b)
{
    return a.x < b.x;
}

//function to calculate distance between 2 points
long double dist(Point p1, Point p2)
{
    return (sqrt((p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y)));
}

//brute force function to find the closest distance between points by one-to-one comparing
Result bruteForce(vector<Point> points, unsigned long int n)
{
    Result tempresult;
    tempresult.d = dist(points[0], points[1]);
    tempresult.a = points[0];
    tempresult.b = points[1];
    for (unsigned long int i=0; i<n; i++)
    {
        for (unsigned long int j=i+1; j<n; j++)
            if (dist(points[i], points[j]) < tempresult.d)
                {
                tempresult.d = dist(points[i], points[j]);
                tempresult.a = points[i];
                tempresult.b = points[j];
                }
    };
    return tempresult;
}

//function to return the minimum value between 2 values entered
long double min(long double v1, long double v2)
{
    if (v1<=v2) return v1;
    else return v2;
}

//function to calculate the minimum distance between points across midpoint borders
Result crossFunction(vector<Point> cross, unsigned long int n, Result tempresult)
{
    for (unsigned long int i=0; i<n; i++)
        for (unsigned long int j = i+1; j < n && (cross[j].x - cross[i].x) < tempresult.d; j++)
            if (dist(cross[i],cross[j]) < tempresult.d)
                {
                tempresult.d = dist(cross[i], cross[j]);
                tempresult.a = cross[i];
                tempresult.b = cross[j];
                }
    return tempresult;
}

//function that includes the critical code of divide-and-conquer to solve the problem
Result closestUtil(vector<Point> points, unsigned long int n)
{
    if (n<=3)
        return bruteForce(points, n);

    Result tempresult, crossresult, finalresult;

    //determine the middle point of the array
    unsigned long int mid = n/2;
    Point midPoint = points[mid];

    vector<Point> points_half1(points.cbegin(), points.cbegin() + mid);
    vector<Point> points_half2(points.cbegin() + mid, points.cend());

    //breaks the array recursively until it reaches n<=3
    Result half1 = closestUtil(points_half1, mid);
    Result half2 = closestUtil(points_half2, n - mid);

    //compares the two closest distances found in both halves and find the minimum of both
    tempresult.d = min(half1.d, half2.d);
    if (tempresult.d == half1.d)
    {
        tempresult.a = half1.a;
        tempresult.b = half1.b;
    }
    else
    {
        tempresult.a = half2.a;
        tempresult.b = half2.b;
    }

    //creates an array to store all points closer to the midpoint than the current local closest value
    vector<Point> cross;
    for (int i=0; i<n; i++)
        if (abs(points[i].x - midPoint.x) < tempresult.d) cross.push_back(points[i]);

    crossresult = crossFunction(cross, cross.size(), tempresult);

    finalresult.d = min(tempresult.d, crossresult.d);

    if (finalresult.d == tempresult.d)
    {
        finalresult.a = tempresult.a;
        finalresult.b = tempresult.b;
    }
    else
    {
        finalresult.a = crossresult.a;
        finalresult.b = crossresult.b;
    }
    return finalresult;
}

Result closestPair(vector<Point>& points)
{
    sort(points.begin(), points.end(), compareX);
    return closestUtil(points,int(points.size()));
};

int main()
{
    unsigned long int n, x, y;
    cout << "Enter the number of points: "; cin >> n;
    cout << "Enter grid size (x y): "; cin >> x >> y;
    if ((n > 1) && (x >= 0) && (y >= 0))
    {
        vector<Point> points;
        Result closest;
        random_device rd;
        default_random_engine generator(rd());
        uniform_int_distribution<long long unsigned> distributeX(0,x);
        uniform_int_distribution<long long unsigned> distributeY(0,y);

        for(long int i=0; i<n; i++)
        {
            Point p;
            p.x = distributeX(generator);
            p.y = distributeY(generator);
            points.push_back(p);
        }

        closest = closestPair(points);

        cout << endl << "The closest distance between points is " << closest.d << " and it is found "
        << "between point (" << closest.a.x << ", " << closest.a.y << ") and point (" << closest.b.x << ", "
        << closest.b.y << ").";
    }
    else cout << "Invalid value(s) entered." << endl;


    return 0;
}
4

0 回答 0