带容差的3D坐标比对 千级条目下的高性能实现需求
高效实现方案:三维网格哈希分桶法
这种方案可以把时间复杂度从暴力匹配的O(N*M)降到O(N+M),对于数千条规模的数据集性能完全足够,甚至支持十万级以上的数据量。
核心思路
因为我们允许的三个维度偏差上限都是±0.1,所以可以把整个三维空间划分为边长为0.1的立方体网格:
- 先预处理参考坐标列表
reference,将每个坐标映射到它所属的网格中,用哈希表存储「网格键 -> 该网格内所有参考坐标」的映射 - 遍历待匹配坐标列表
coords时,仅需要检查当前坐标所属网格,以及周围相邻的共27个网格(三维空间333)内的参考坐标,逐一精确校验偏差是否符合要求即可,无需遍历全部参考坐标
实现代码(C#)
// 精度阈值 const double Tolerance = 0.1; // 预处理参考坐标的哈希字典 var refGrid = new Dictionary<(int xKey, int yKey, int zKey), List<(double x, double y, double z)>>(); // 计算坐标所属网格键的方法 static int GetGridKey(double val) => (int)Math.Floor(val / Tolerance); // 第一步:填充参考坐标的网格字典 foreach (var p in reference) { var key = (GetGridKey(p.x), GetGridKey(p.y), GetGridKey(p.z)); if (!refGrid.TryGetValue(key, out var list)) { list = new List<(double x, double y, double z)>(); refGrid[key] = list; } list.Add(p); } // 第二步:筛选符合条件的实测坐标 var result = new List<(double x, double y, double z)>(); foreach (var p in coords) { bool isMatch = false; // 计算当前点x/y/z三个维度需要检查的网格键范围(各±1,共3个值) int xMin = GetGridKey(p.x - Tolerance); int xMax = GetGridKey(p.x + Tolerance); int yMin = GetGridKey(p.y - Tolerance); int yMax = GetGridKey(p.y + Tolerance); int zMin = GetGridKey(p.z - Tolerance); int zMax = GetGridKey(p.z + Tolerance); // 遍历所有可能的27个网格 for (int xk = xMin; xk <= xMax; xk++) { for (int yk = yMin; yk <= yMax; yk++) { for (int zk = zMin; zk <= zMax; zk++) { if (refGrid.TryGetValue((xk, yk, zk), out var refPoints)) { // 精确校验偏差 foreach (var rp in refPoints) { if (Math.Abs(p.x - rp.x) <= Tolerance && Math.Abs(p.y - rp.y) <= Tolerance && Math.Abs(p.z - rp.z) <= Tolerance) { isMatch = true; goto EndCheck; // 找到匹配就跳出所有循环 } } } } } } EndCheck: if (isMatch) { result.Add(p); } }
性能说明
- 预处理阶段仅需要遍历一次参考坐标列表,开销为
O(M),M为参考坐标数量 - 匹配阶段每个实测坐标最多只需要检查27个网格,每个网格内的参考坐标数量通常极少,开销接近
O(N),N为实测坐标数量 - 对于双列表均为数千条的场景,整套逻辑执行耗时通常在1ms以内,远高于暴力匹配的性能
内容的提问来源于stack exchange,提问作者dba
相关产品推荐
相关产品推荐

