2015-08-23 78 views
1

我有两个二进制数组,一个大小为34(模式),另一个大小为10000(目标)。 我想看看是否有任何模式在目标与阈值(如最多4个不匹配) 和返回匹配数(没有重叠发生,如果一个匹配,然后下一个匹配将远离800个单元格)。 我知道这是一种近似匹配问题,但我不知道使用哪种算法具有最佳性能。我做了什么至今:(方法LIKE2具有更好的性能)比较两个二进制数组与阈值(近似匹配)

void compare (bool *target, int t, bool * pattern , int p , int threshold) 
{ 
    for(int i =0;i<t-p;i++){ 
     if(like(target+i,pattern,p,threshold)){ 
      return true; 
     } 
    } 
    return false; 
} 

void like2(bool *target, bool * pattern , int p , int threshold){ 
    int k =0; 
    for(int i =0;i<p, ;i++){ 
     k+= target[i]^pattern [i]; 
    } 
    return (k<=threshold); 
} 
void like(bool *target, bool * pattern , int p , int threshold){ 
    int k =threshold; 
    for(int i =0;i<p,k>=0 ;i++){ 
     if(target[i]!=pattern[i]){ 
      --k; 
     } 
    } 
    return (k >=0); 
} 

我试过用字符串匹配算法,如克努特莫里斯普拉特算法,但它们是精确匹配,并改变它们近似匹配算法是一个很难的方法。

+0

当'k'已经超过阈值时加入提前返回 – timrau

+0

它不会提高性能! – abdolahS

+0

@abdolahS你是什么意思,如果有一场(接近)比赛,那么下一场比赛至少会有800“小格”?你是否贪婪地从左到右搜索大串中的(接近)比赛,然后如果你找到一个,那么你在大串中向右移动800个位置来寻找下一个接近的匹配? – user2566092

回答

3

将模式组合成(长整数)整数pattern_int,因为它只有34位。现在循环通过target。在k = 0处,您将target位0-33组合为模式,至combined_int。当你到了k + 1重新计算combined_int如下:

combined_int = (combined_int << 1) & ~(1 << 34) | target[k + 34]; 

基本上,你一个位置(因为你提前从kk + 1),明确转移出来的不再视为有位,并添加一个新的。

要查看匹配是否足够接近模式,请使用异或combined_intpattern_int并计数1位。我相信后者是在现代CPU的单一指令下完成的。

编辑:当你建立初始组合,确保pattern[0]pattern_int最终成为最显著位,同样为target。否则,您需要更改相应的combined_int重新计算的方式。

+0

谢谢,这是一个很好的答案,但模式长度超过长位长度的情况怎么样?(例如100位而不是34位) – abdolahS

+1

您可以通过使用'combined_int'和'pattern_int'几个整数(或一列整数),并将一位从低位移到高位。但是,性能也会下降,但是对于两个整数(100位),它应该比逐个元素的解决方案更好,我猜。但总的来说,这并没有太好地扩大,是的。它通常取决于元素内部循环的预期大小。总体而言,模式大小比例的阈值越大,我描述的按位算法越好。 – doublep

+1

@abdolahS - 有几个128位寄存器,如果这对您有用。 –