等同于多个值的最佳算法性能

时间:2012-06-18 14:36:03

标签: android algorithm

我正在开发一个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检查每个输入。但我不认为在这种情况下有两种方法是好的。 所以我需要你的帮助,如果你有与我相同的情况,你已经解决了,或者你有更好或最好的解决方案,请告诉我。

提前谢谢你。抱歉,如果我的英语不好。

2 个答案:

答案 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 tableopen addressing碰撞解决方案):

  1. 为简单起见,假设您使用y值来获取跳转位置(如果区域垂直分开,则应减少检查次数)。假设您的屏幕分辨率为600x800,您可以将y除以60以获得~13个插槽。如果您使用的是8位表,则相当于每个插槽约18个项目(round(800/60)=13round(255/13)=18)。

  2. 为了加快计算速度,您应该保持一切简单,这样您就可以使用以下方式获取插槽编号:

    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);
    
  3. 现在你有了插槽索引,只需跳转到哈希表并检查,直到没有其他项目要检查:

    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;
    }
    
  4. 需要在init期间以类似的方式创建哈希表:对于24个区域中的每个区域,计算其哈希(槽)索引。如果哈希表中的位置被占用,只需增加1直到找到空白点。 注意:您是否必须将每个区域添加到所有重叠的广告位。最简单的方法是将其添加到广告位ss-1s+1

  5. 您的循环目前平均执行 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