【问题标题】:Closest pair of points nlogn algorithm memory problem最近的点对nlogn算法内存问题
【发布时间】:2020-05-02 16:05:07
【问题描述】:

我正在尝试创建一个程序来计算一对点之间的最小距离,但我不知道如何使我的代码工作。它有时似乎适用于某些 n 输入,但并非始终如一。在尝试解决此问题时,我遇到了堆损坏错误、错误的数组新长度以及最近的严重错误 c0000374。我猜这是非常愚蠢的事情,但我无法提出解决方案。

代码基于: https://www.geeksforgeeks.org/closest-pair-of-points-onlogn-implementation/

#include <iostream>
    #include <random>
    #include <stdlib.h>
    #include <math.h>
    #include <algorithm>
    #define MAX 1;
    struct Point {
        float x;
        float y;
        Point()
        {
            this->x = 0;
            this->y = 0;
        }
        Point(float x, float y) {
            this->x = x;
            this->y = y;
        }
        Point *operator=(const Point *other)
        {
            this->x = other->x;
            this->y = other->y;
            return this;
        }
    };
    void merge(Point* &arr, int l, int m, int r) {
        int i, j, k;
        int n1 = m - l + 1;
        int n2 = r - m;
        Point *L = new Point[n1];
        Point *R = new Point[n2];
    
        for (i = 0; i < n1; i++) {
            L[i] = &arr[l + i];
        }
        for (j = 0; j < n2; j++) {
            R[j] = &arr[m + 1 + j];
        }
        i = 0;
        j = 0;
        k = l;
        while (i < n1 && j < n2)
        {
            if (L[i].x <= R[j].x)
            {
                arr[k] = L[i];
                i++;
            }
            else
            {
                arr[k] = R[j];
                j++;
            }
            k++;
        }
        while (i < n1)
        {
            arr[k] = L[i];
            i++;
            k++;
        }
    
        while (j < n2)
        {
            arr[k] = R[j];
            j++;
            k++;
        }
    }
    
    void mergeSort(Point* &arr, int l, int r)
    {
        if (l < r)
        {
            int m = l + (r - l) / 2;
            mergeSort(arr, l, m);
            mergeSort(arr, m + 1, r);
            merge(arr, l, m, r);
        }
    }
    int  compareX(Point a, Point b) {
        return ((float)a.x >= (float)b.x) ? 1 : -1;
    };
    float dist(Point p1, Point p2)
    {
        return sqrt((p1.x - p2.x)*(p1.x - p2.x) +
            (p1.y - p2.y)*(p1.y - p2.y)
        );
    }
    float stripClosest(Point* &strip, int size, float d)
    {
        float min = d; 
        for (int i = 0; i < size; ++i)
            for (int j = i + 1; j < size && (strip[j].y - strip[i].y) < min; ++j)
                if (dist(strip[i], strip[j]) < min)
                    min = dist(strip[i], strip[j]);
        return min;
    }
    float min(float x, float y)
    {
        return (x < y) ? x : y;
    }
    
    float bruteForce(Point P[], int n)
    {
        float min = MAX;
        for (int i = 0; i < n; ++i)
            for (int j = i + 1; j < n; ++j)
                if (dist(P[i], P[j]) < min)
                    min = dist(P[i], P[j]);
        return min;
    }
    float closestUtil(Point P[], Point Pi[], int n)
    {
        if (n <= 3)
        {
            return bruteForce(P, n);
        }
        else
        {
            int mid = n / 2;
            Point midPoint = P[mid];
            int li = 0, ri = 0;
            Point* Pyl = new Point[mid+1];
            Point* Pyr = new Point[n - (mid -1)];
            Point* strip = new Point[n];
            for (int i = 0; i < n; i++)
            {
                if (P[i].y <= midPoint.y)
                    Pyl[li++] = Pi[i];
                else
                    Pyr[ri++] = Pi[i];
            }
    
            float dl = closestUtil(P, Pyl, mid);
            float dr = closestUtil(P + mid, Pyr, n - mid);
            float d = min(dl, dr);      
            int j = 0;
            for (int i = 0; i < n; i++)
                if (abs(P[i].y - midPoint.y) < d)
                    strip[j] = Pi[i], j++;
            return min(d, stripClosest(strip, j, d));
        }
    }
    
    int main() {
    
        int n;
        std::cout << "Input the amount of points" << std::endl;
        std::cin >> n;
        Point* arr = new Point[n];
        std::default_random_engine generator;
        std::uniform_real_distribution<float> distribution(0.0, 1.0);
        for (int i = 0; i < n; i++)
        {
            float xi = distribution(generator);
            float yi = distribution(generator);
            arr[i].x = xi;
            arr[i].y = yi;
        }
        mergeSort(arr, 0, n - 1);
        for (int i = 0; i < n; i++)
            std::cout << arr[i].x << std::endl;
        std::cout << bruteForce(arr, n) << std::endl;
        std::cout << closestUtil(arr, arr, n);
        return 0;
    }

【问题讨论】:

  • 你为什么要用这么多指针?
  • 首先,将Point *operator=(const Point *other) 更改为Point &amp;operator=(const Point &amp;other) 并在其末尾返回*this
  • Formerlyknownas_463035818 对此并没有很好的答案,在过去的几个小时里,我一直在尝试几乎所有想到的东西,这是我代码的最新状态。 @goodvibration 改变了它,除了 n=​​5 或 n=15 之类的某些情况外仍然不起作用
  • 这是很多有很多问题的代码,其中很多与不使用std::vector有关
  • 在编程时,您需要学习将问题拆分成更小的块。整个代码太多了,无法一口气完成。专注于单独的部分,编写测试,只有当你知道你已经拥有的代码可以正常工作时才继续。

标签: c++ pointers memory dynamic


【解决方案1】:

在 C++ 中,我们有 std::vector,它消除了对所有 news 的需求。我们还有非常有用的assert 宏。你提到的网站忽略了所有好的做法,并且包含很多非常糟糕的代码示例,最好避免。

我不会修复您的代码,但会给您一个可能有用的提示。如果你用

重新编译代码
clang++ -fsanitize=address -g 1.cpp

运行它,你会看到这样的:

WRITE of size 8 at 0x606000000120 thread T0
    #0 0x4937cf in __asan_memcpy (/tmp/0/a.out+0x4937cf)
    #1 0x4c886b in closestUtil(Point*, Point*, int) /tmp/0/1.cpp:133:31
    #2 0x4c9246 in main /tmp/0/1.cpp:172:22
    #3 0x7fbbc46ddb6a in __libc_start_main /build/glibc-KRRWSm/glibc-2.29/csu/../csu/libc-start.c:308:16
    #4 0x41c3d9 in _start (/tmp/0/a.out+0x41c3d9)

位置1.cpp:133 对应您代码中的这一行:

Point* Pyl = new Point[mid+1];
...
for (int i = 0; i < n; i++)
{
    if (P[i].y <= midPoint.y)
        Pyl[li++] = Pi[i];          // << ERROR IS HERE
    else
        Pyr[ri++] = Pi[i];
}

发生了什么事?如果您在if 之前插入上述assert(li &lt; mid + 1);,重新编译并重新运行程序,您会看到断言失败。那就是您在其边界之外访问Pyl 数组,这是未定义的行为。仔细分析你的代码会告诉你原因。修复此错误后,您可以重复上述过程以查找其他错误(如果有)。

【讨论】:

  • 将该代码转换为正确的 C++ 后,我确认了错误。 Visual C++ 报告一个向量越界错误。
  • @Evg 感谢您的帮助,遗憾的是,在处理了这些值之后,我仍然无法使其正常工作。我尝试根据 n 是偶数还是奇数来切换中点,更改 Pyl 和 Pyr 大小,
  • std::vector 不是“现代” ;)
  • @foreknownas_463035818,确实如此。
猜你喜欢
  • 1970-01-01
  • 2011-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-04
  • 1970-01-01
相关资源
最近更新 更多