Algorithm 在矩形中计数点
我有很多(数十亿)2D点可以预处理,我想回答以下形式的查询: 给定矩形的所有四个角,输出矩形内的点数 矩形可以是任意方向(这意味着矩形的轴可以是任意角度,而不仅仅是水平或垂直方向) 有没有一个快速实用的算法 更新。是否有任何数据结构来存储可证明查询处于次线性时间的点Algorithm 在矩形中计数点,algorithm,Algorithm,我有很多(数十亿)2D点可以预处理,我想回答以下形式的查询: 给定矩形的所有四个角,输出矩形内的点数 矩形可以是任意方向(这意味着矩形的轴可以是任意角度,而不仅仅是水平或垂直方向) 有没有一个快速实用的算法 更新。是否有任何数据结构来存储可证明查询处于次线性时间的点 更新II答案似乎是坚定的否定。在任何情况下都接受最流行的答案。您需要的是某种二进制空间分区数据结构。这将为您提供一个候选列表,您可以对其进行真正的“多边形中的点”测试 我建议您确保这是您真正应该自己编写的代码。例如,许多数据库都内置
更新II答案似乎是坚定的否定。在任何情况下都接受最流行的答案。您需要的是某种二进制空间分区数据结构。这将为您提供一个候选列表,您可以对其进行真正的“多边形中的点”测试 我建议您确保这是您真正应该自己编写的代码。例如,许多数据库都内置了这种功能。您的数据实际上是否驻留在数据库中?可以吗?(重新发明轮子毫无意义…)
您可以在这里看到多边形中的点问题的一个很好的答案:我建议找到一个可以应用于空间的旋转+移位变换,这样矩形的一个角位于
(0,0)
中,两条边沿着x
和y
轴
现在,您检查这些点,应用相同的转换,只需检查0
和0
旧答案(如果您无法预先预处理这些点):
- 将矩形刻在包含矩形中,边/边的方向为xy轴
- 快速排除它之外的所有点
- 使用此处解释的原理:使用矩形的四条边(注意:由于您总是使用相同的矩形检查所有点,因此可以预先计算一些值)
是我们的输入矩形rect
- 假设您有
,它检查点是否在矩形内。你可以用我上面提到的那个f1(点,矩形)
- 假设您有
,这可以说明shape是否完全包含在rect中,或者rect是否完全包含在shape中,或者shape和rect是否相交f2(shape,rect)
- 形状将是具有一定数量边的多边形(不高或与n成比例,因此我们可以假设
是f2
),或2D平面中由两条边分隔并延伸到无限远的区域(例如,由xy轴正截面分隔的区域)O(1)
- 假设您有很多时间来预处理点,但不是无限的。假设我们能负担得起一个O(n*log(n))算法
log(n)
所以我们想把二维平面分成m
形状,每个形状包含p
点。在运行时,我们用f2检查每个形状,我们可以有4种情况:
(O(p))
,我结束李>
(O(p))
,我继续O(p)+O(m)
。考虑到p*m=n
,如果我们选择p=m=sqrt(n)
我们得到O(sqrt(n))
,这是我们用这种方法能得到的最好结果。(注意:我们执行f1的次数?这个数字实际上取决于矩形的形状,因此,例如,如果矩形非常长,它将与许多区域相交,导致对f1的多次调用。但是,我认为我们可以假设矩形的度量值的顺序与n
或的顺序不同>sqrt(n)
甚至log(n)
:n
是巨大的。)
我们可以从这里加强;例如,我们可以说形状之间有邻接,当我第一次发现形状和矩形之间有重叠时,我只检查相邻的形状。然而,我们必须检查的形状的平均数量将在p/2左右,并且O(p/2)=(O(p))
。因此没有有效的收益
真正的好处是,如果我们在形状中加入一些层次结构
首先,我检查所有的点,找到我的界限值max_x,max_y,min_x,min_y。(假设这些边界为>>n。如果我们可以对点分布有先验知识,那么我们可以针对的优化将完全不同)
我们将我们的空间划分为形状,每个形状包含(大约)对数(n)个点。我们首先使用xy轴将2D平面划分为4个形状(我也可以根据边界值居中)。这将是我们倒置金字塔的第一层。
周期性地:对于每个连续的区域
public class DataPoint
{
double X, Y;
...
}
public bool IsInBoundingBox(Point p1, Point p2, Point p3, Point p4)
{
// assume p1, p2, p3, p4 to be sorted
return (X>p1.X && X<p3.X && Y>p4.Y && Y<p2.Y);
}
// sort points of QueryRectangle: p1 is left-most, p2 is top-most, p3 is right-
// most, and p4 to be bottom-most; if there is a tie for left-most, p1 should
// be the bottom-left corner, p2 the top-left corner, p3 the top-right corner,
// and p4 the bottom-right corner
// See if the QueryRectangle in question is aligned with the grid; if it is,
// then the set of DataPoints that lie within the BoundingBox are within the
// QueryRectangle and no further calculation is needed
if (p1.X == p2.X || p1.X == p3.X || p1.X == p4.X)
{
// is orthogonal (aligned with axes)
foreach(DataPoint dp in listDataPoints)
if(dp.IsInBoundingBox())
{
// dp is in QueryRectangle; perform work
}
}
else
{
foreach(DataPoint dp in listDataPoints)
if(dp.IsInBoundingBox())
{
// perform further testing to see if dp is in QueryRectangle
}
}
// sort points of QueryRectangle: p1 is left-most, p2 is top-most, p3 is right-
// most, and p4 to be bottom-most; if there is a tie for left-most, p1 should
// be the bottom-left corner, p2 the top-left corner, p3 the top-right corner,
// and p4 the bottom-right corner
public class DataPointList : List<DataPoint>
{
public List<DataPoint> GetPointsInRectangle(Point p1, Point p2, Point p3, Point p4)
{
List<DataPoint> tempListDataPoints = new List<DataPoint>();
foreach(DataPoint dp in this)
if(dp.IsInBoundingBox()) tempListDataPoints.Add(dp);
if (!(p1.X == p2.X || p1.X == p3.X || p1.X == p4.X))
{
// needs transformation
tempListDataPoints.TranslateAll(-1 * p1.X, -1 * p1.Y);
tempListDataPoints.RotateAll(/* someAngle derived from the arctan of p1 and p2 */);
// Note: you should be rotating counter-clockwise by some angle >0 but <90
// the new p1 will be 0,0, but p2, p3, and p4 all need to undergo the same transformations
// transP1 = new Point(0,0);
// transP2 = new Point(p2.Translate(-1 * p1.X, -1 * p1.Y).Rotate(/* someAngle derived from the arctan of p1 and p2 */));
// transP3 = ...; transP4 = ...;
foreach(DataPoint dp in tempListDataPoints)
if (!(dp.X>transP1.X && dp.X<transP3.X && dp.Y>transP1.Y && dp.Y<transP3.Y)) tempListDataPoints.Remove(dp);
}
else
{
// QueryRectangle is aligned with axes, all points in bounding box
// lie within the QueryRectangle, no need for transformation or any
// further calculation
// no code needs to go here, but you may want to keep it around for notes
}
return tempListDataPoints;
}
}
A D a
B E b
C F c
d = 1/(AE − BD)
A' = Ed
B' = −Bd
C' = (BF − EC)d
D' = −Dd
E' = Ad
F' = (DC − AF)d
a' = b' = 0
c' = 1
|(P1.x, P1.y, 0)x(P2.x, P2.y, 0)[3]|+
|(P2.x, P2.y, 0)x(P3.x, P3.y, 0)[3]|+
|(P3.x, P3.y, 0)x(P4.x, P4.y, 0)[3]|+
|(P4.x, P4.y, 0)x(P1.x, P1.y, 0)[3]|