我正在阅读C ++中的Robert Sedwick Algorithms的一本书。以下是关于复合数据结构的书中给出的例子。
问题陈述: 给定“d”,我们想知道单位平方中一组N个点中有多少对可以通过长度小于“d”的直线连接。
使用逻辑的程序将单位squre划分为网格,并维护链接列表的二维数组,其中一个列表对应于每个网格方块。选择网格足够精细,使得距离“d”内的所有点都在同一网格方格或相邻网格中。
我的问题是
- 为什么作者在malloc2d(G + 2,G + 2)中分配G + 2?
- 在gridinsert函数中为什么作者执行以下语句int X = x * G + 1; int Y = y * G + 1; ?
- 在for循环中我们为什么要将其初始化为X-1并将j初始化为Y-1?
- 在代码中,我们在相同网格方格或相邻网格中保持距离d内的点?
醇>
通过简单的示例请求您的帮助,以了解以下程序。
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
using namespace std;
float randFloat() {
return 1.0*rand()/RAND_MAX;
}
struct myPoint {
float x;
float y;
};
float myDistance(myPoint a, myPoint b) {
float dx = a.x - b.x, dy = a.y - b.y;
return sqrt(dx*dx + dy*dy);
}
struct node {
myPoint p; node *next;
node(myPoint pt, node* t) {
p = pt; next = t;
}
};
typedef node *link;
static link **grid = NULL;
link **malloc2d(int r, int c) {
link **t = new link*[r];
for (int i = 0; i < r; i++) {
t[i] = new link[c];
}
return t;
}
static int G, cnt = 0;
static float d;
void gridinsert(float x, float y) {
int X = x*G+1;
int Y = y*G+1;
myPoint p;
p.x = x; p.y = y;
link s, t = new node(p, grid[X][Y]);
for (int i = X-1; i <= X+1; i++)
for (int j = Y-1; j <= Y+1; j++)
for (s = grid[i][j]; s != 0; s = s->next)
if (myDistance(s->p, t->p) < d) cnt++;
grid[X][Y] = t;
}
int main(int argc, char *argv[]) {
int i;
int N = 10;
d = 0.25;
G = 1/d;
grid = malloc2d(G+2, G+2);
for (i = 0; i < G+2; i++)
for (int j = 0; j < G+2; j++)
grid[i][j] = 0;
for (i = 0; i < N; i++)
gridinsert(randFloat(), randFloat());
cout << cnt << " pairs within " << d << endl;
return 0;
}
答案 0 :(得分:5)
我们的想法是检查所有相邻的网格单元格。但边境小区没有邻接。因此,为了避免棘手的边界检查,我们将网格扩展2个额外的单元格 - 在第一个单元格之前和之后的单元格之后这些单元格是“虚拟”并且永远不会包含任何点 - 它们只是为了简化算法并为边界单元提供邻接。
(X,Y) - 包含此点的网格中单元格的坐标(索引)。根据第1页,我们必须从单元格(1,1)开始放置点,而不是(0,0)。 (0,0)和任何其他边界点都是虚拟的。
因为我们检查网格的所有相邻单元格。 (X,Y)的相邻单元是(X-1,Y-1),(X,Y-1),(X + 1,Y-1)等(X + 1,Y + 1)。这就是为什么我们有从X-1到X + 1和Y-1到Y + 1的循环。
我们不维护它们,只检查任何输入点与现有设置,并在每次匹配距离时递增计数器cnt
。问题条件不需要保留这些对的列表。如果您需要保留点列表,则应修改gridinsert()
,例如将(s->p, t->p)
放置在循环内的某个容器中,而不是增加cnt++
。