一种可能的算法使用空间“桶”来减少计算时间。
它不会做特殊的线程技巧,但会减少很多用户比较(取决于桶的大小)。
我们的想法是为每个彼此相距不远的用户放入相同的“桶”,并在“桶”上创建一个索引,以便以低成本获取相邻的“桶”。
假设我们有
class User{
long userId;
GPS start;
GPS stop;
}
class GPS{
long x;
long y;
}
首先我们为索引用户创建一个类:
class BucketEntity implements Comparable<BucketEntity>{
User origin;
long x;
long y
}
class Bucket extends Set<BucketEntity {
}
我们将为每个用户创建两个 BucketEntity,一个用于“开始”,一个用于“结束”。我们会将这些 BucketEntity 存储到一个特殊的索引数据结构中,以便轻松检索最近的其他 BucketEntity。
class Index extends ConcurrentHashMap<BucketEntity,Bucket> {
// Overload the 'put' implementation to correctly manage the Bucket (null initialy, etc...)
}
我们只需要在 BucketEntity 类中实现 'hash' (和 'equals' 方法。如果两个 BucketEntity 距离不远,'hash' 和 'equals' 的规范是相同的)其他。对于给定的 BucketEntity,我们还希望能够计算在空间上与另一个 Bucket 相邻的 Bucket 的“哈希”函数。
要获得“哈希”和“等于”的正确行为,一个不错/快速的解决方案是进行“精度降低”。简而言之,如果您有“x = 1248813”,则将其替换为“x=124”(除以 1000),就像将 GPS 米精度更改为 GPS 公里精度一样。
public static long scall = 1000;
boolean equals(BucketEntity that)
{
if (this == that) return true;
if (this.x / scall == that.x / scall &&
this.y / scall == that.y / scall)
return true;
return false;
}
// Maybe an 'int' is not enough to correctly hash your data
// if so you have to create you own implementation of Map
// with a special "long hashCode()" support.
int hashCode()
{
// We put the 'x' bits in the high level, and the 'y' bits in the low level.
// So the 'x' and 'y' don't conflict.
// Take extra-care of the value of 'scall' relatively to your data and the max value of 'int'. scall == 10000 should be a maximum.
return (this.x / scall) * scall + (this.y / scall);
}
正如你在hashCode()方法中看到的那样,彼此靠近的Bucket确实接近hashCode(),如果我给你一个Bucket,你也可以计算空间相邻的Bucket hashCode()。
现在您可以获得与给定 BucketEntity 位于同一 Bucket 中的 BucketEntity。要获取相邻的存储桶,您需要在 BucketEntity 的存储桶周围创建 9 个虚拟 BucketEntity 到 'get()' Bucket/null。
List<BucketEntity> shortListToCheck = // A List not a Set !
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)+1 , (y/scall)+1 )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)+1 , (y/scall) )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)+1 , (y/scall)-1 )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)+1 , (y/scall)+1 )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall) , (y/scall) )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)-1 , (y/scall)-1 )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)-1 , (y/scall)+1 )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)-1 , (y/scall) )));
shortListToCheck.addindex.get(new BucketEntity(user, (x / scall)-1 , (y/scall)-1 )));
get() 匹配9个虚拟BucketEntry的所有Bucket(可以为null)。
对于给定 9 个存储桶的每个用户,按照您在问题中提供的方式计算距离。
然后玩'scall'。你能看到吗,这里对多线程没有真正的限制。也许下一个级别的算法优化是基于自适应缩放大小的自适应/递归桶大小。