我正在开发一个Android应用程序。我在我的应用程序中遇到了一个重要方法的问题,因为我无法使用最佳算法将许多输入等同于许多数据。
以下是该方案:
方法的输入是覆盖方法onTouchEvent()
的坐标,因此当触摸屏幕并在其上移动手指时,输入将是如此之多。
我必须将那么多坐标等同于数组中的24个值。
数组中的值也是一个坐标。因此,当输入与数组中的值具有相同的值时,它会得分。
这是我使用的代码:
public void checkCoordinate(float x, float y){
int sensitivity = 30;
for(int z = 0; z < 24; z++){
if(x > (cxy[z][0]-sensivity) && x < (cxy[z][0]+sensivity) && y > (cxy[z][1]-sensivity) && y < (cxy[z][1]+sensivity)){
points += 1;
Log.i("CheckCoordinate", "Total Points = "+points);
}
}
我有两种方法可以将它等同起来。一,使用上面的算法,或使用24 if检查每个输入。但我不认为在这种情况下有两种方法是好的。 所以我需要你的帮助,如果你有与我相同的情况,你已经解决了,或者你有更好或最好的解决方案,请告诉我。
提前谢谢你。抱歉,如果我的英语不好。
答案 0 :(得分:1)
有了这个说法,你的通用想法是正确的。问题是它现在可以以某种方式进行优化吗?
我们可以在这里采用许多方法。诀窍在于您安排数据的方式。在您当前的情况下,您正在做一个中心点,灵敏度变量就是您的跨度。可以想象,第一个优化不是使用从中心点左右上下移动的灵敏度,而是可以实现左上角,其中跨度仅从左上角向右和向下移动。您的if语句将成为:
if(x > cxy[z][0] && x < (cxy[z][0]+sensivity) && y > cxy[z][1] && y < (cxy[z][1]+sensivity))
那么这对你有什么用呢: 上面的优化允许您保持相同的总数据量,但每次检查除去2个数学运算。考虑到您的输入参数都是浮点,这可以节省相当多的时间。
如果您正在进行所有基于像素的操作,那么这将带我进行下一次优化。使用整数而不是浮点进行所有计算,这也将大大加快您的整体算法时间。
现在可以进行进一步的优化,如果您愿意花更多的RAM来获得更好的性能,那么您可以为每个区域设置一个左上角和右下角,而不是每个区域有1个点。这会使你的if语句看起来像下面这样:
if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1])
where tlxy is the array of top-left points, brxy is the array of bottom-right points
and z is still the "region" you are checking against
这有何帮助: 正如您在上面的if语句中所看到的,现在这绝对没有明确的数学运算。为了支持这种算法,你需要愿意花费2倍的内存,就像最初的数组cxy一样。
现在在你的循环中,你将经历所有24个区域点。如果您知道某些区域没有重叠,那么一个点实际上一次只能落入1个区域。通过在增加点数的点处突破for循环,可以在大多数x y输入点上节省一些时间。这看起来如下:
public void checkCoordinate(float x, float y){
for(int z = 0; z < 24; z++){
if(x > tlxy[z][0] && x < brxy[z][0] && y > tlxy[z][1] && y < brxy[z][1]){
points += 1;
break;
}
}
}
以上只会工作IFF您知道确定没有重叠区域(甚至没有边缘。
在最终优化中我可以看到可能有潜力。根据您所在地区的情况,您可以预先将所有地区划分为象限。这样,您可以测试x点位于屏幕的左侧或右侧,然后测试y点位于顶部或底部。如果您的区域分布相当均匀,则可能会将测试时间减少4,因为您不仅需要测试象限内的区域(如果给定的统计分布是我所说的)。在最坏的情况下,所有区域都位于一个象限中,并且您测试的所有点都在该象限中,在这种情况下,从复杂性的角度来看问题并不比以前更差。它只是在输入x和y上添加了一个设置测试。
我希望这能为您提供足够的信息,至少可以开始使用!!!
答案 1 :(得分:0)
对于24个值,这可能是一种矫枉过正,但您可能还想考虑使用普通数组hash table(open addressing碰撞解决方案):
为简单起见,假设您使用y
值来获取跳转位置(如果区域垂直分开,则应减少检查次数)。假设您的屏幕分辨率为600x800,您可以将y
除以60以获得~13个插槽。如果您使用的是8位表,则相当于每个插槽约18个项目(round(800/60)=13
,round(255/13)=18
)。
为了加快计算速度,您应该保持一切简单,这样您就可以使用以下方式获取插槽编号:
int yi = (int)y;
// this is your "hash function". depending on your actual data,
// you might want to modify it to get a lesser chance of collisions
byte slot = (byte)((yi / 60) * 18);
现在你有了插槽索引,只需跳转到哈希表并检查,直到没有其他项目要检查:
rectangle r;
int yi = (int)y;
for (byte slot=(byte)(yi / 26); slot < 256; slot++)
{
r = hashtable[slot];
// is this an empty slot?
if (r.brxy == 0)
break;
// perform exact check
if (r.left < x && x < r.right &&
r.top < y && y < r.bottom)
break;
}
需要在init期间以类似的方式创建哈希表:对于24个区域中的每个区域,计算其哈希(槽)索引。如果哈希表中的位置被占用,只需增加1直到找到空白点。 注意:您是否必须将每个区域添加到所有重叠的广告位。最简单的方法是将其添加到广告位s
,s-1
和s+1
。
您的循环目前平均执行 12次查找,而基于散列的方法执行单个哈希计算,并且平均只需要两次或三次查找(哈希表据说具有{{1平均复杂性,假设一个好的哈希函数)。
示例强>
理想情况下,您的O(1)
应该类似于:
hashtable
因此,如果您的接触点为hashtable[0]: rectangle(0, 0, 60, 60);
hashtable[1]: rectangle(20, 20, 80, 80);
hashtable[2]: (empty)
hashtable[3]: (empty)
...
// next slot starts at [18]
hashtable[18]: rectangle(20, 20, 80, 80); // this region is in slots 0 and 1
hashtable[19]: rectangle(30, 70, 90, 130);
hashtable[20]: rectangle(400, 70, 460, 130);
hashtable[21]: (empty)
...
,则计算将继续如下:
(430, 100)
性能仅取决于所选的哈希函数:
如果您有许多具有相似a) slot = (byte)((100/60) * 18) = 18;
b) check hashtable[18], overlapping? no
c) check hashtable[19], overlapping? no
c) check hashtable[20], overlapping? yes, found after 3 checks
坐标的项目,您可能会在某些插槽中遇到许多冲突:这就是选择良好哈希函数的重要原因。如果区域已修复,您甚至可以创建perfect hash。