加快搜索最佳二进制匹配数

时间:2014-01-24 19:07:33

标签: algorithm search data-structures

我有一个256位值的数组。该数组是巨大的(数百万条记录),但它很少被修改,它适合内存。对于给定的256位数,我想查找是否存在至少N位相等的记录。例如,10000和01111的0位相等,1000和1001的3位相等。总是N> 128,或者更确切地说,N> 140.我不需要找到一个特定的号码,我只需要查看列表中是否存在这样的号码。

是否有某种数据结构或某种索引可以某种方式加速搜索?

2 个答案:

答案 0 :(得分:1)

要解决的算法是O(n)。您唯一的选择是循环遍历数组,直到找到与您的目标匹配的数字。

现在,我们如何找到两个数字是否匹配?最有效的方法是使用按位运算。例如,我编写了一个适用于64位长数字的代码:

int compare(long l1, long l2)
{
    //Use xor to get what bits are the same
    long xor = ~ (l1 ^ l2);

    //count the number of bits with value = 1
    int count = 0;
    while(xor != 0)
    {
        //check if the right bit is 1, using & operator beetween our number and 0000001
        if(xor & 1 > 0) count++;

        //shift right the bits
        xor = xor >> 1
    }

    return count;
}

根据您的256位数字的实现方式,可以调整此比较。 当您到达count >= N时,优化可能是打破while循环。

您可以查看this question以查找更有效的方法来计算值为1的位。

希望它有所帮助!

答案 1 :(得分:1)

我可能错了,但看起来您可以将数据索引为按位trie,对于您的情况,它与结构中的二叉树相同,但解释不同。这是插图(source):

enter image description here

为了简单起见,让我们考虑你的256位数字,就像256个数字的矢量一样(当然也是二进制数)。拥有如上所述的树,您可以通过向下走树并测试后续分支(“0”或“1”)是否存在,找到数据集中是否存在256步或更少的特定向量。像这样的东西(代码非常原始,但你应该知道):

def exists(node, v, i):
    """Checks if subvector of v starting from index i exists in 
       sub-tree defined by node
    """
    if i == len(v): 
        return True
    elif v[i] == 0 and node.left: 
        return exists(node.left, v, i + 1)
    elif v[i] == 1 and node.right: 
        return exists(node.right, v, i + 1)
    else: 
        return False

在每个步骤中,我们根据v的当前值元素决定向左或向右分支的位置。但是您还需要处理多达K个不同的元素。好的,那么为什么不使用错误计数并处理两个分支?

def exists(node, v, i, err_left=K):
    """Checks if subvector of v starting from index i exists in 
       sub-tree defined by node with up to err_left errors.
    """
    if i == len(v): 
        return True
    elif v[i] == 0: 
        if node.left:
            return exists(node.left, v, i + 1, err_count)
        elif node.right: 
            return exists(node.left, v, i + 1, err_left - 1)  # proceed, but decrease 
                                                              #   errors left
        else: 
            return False            
    elif v[i] == 1: 
        if node.right:
            return exists(node.right, v, i + 1, err_count)
        elif node.left: 
            return exists(node.right, v, i + 1, err_left - 1)  # proceed, but decrease 
                                                               #   errors left
        else: 
            return False 
    else: 
        return False

此算法的运行时间在很大程度上取决于您的设置。在最坏的情况下(K = 256)它仍然是O(n)(你需要检查每个分支),但是这个时间随着K的减小而迅速下降(小K几乎为O(log n))。 K~128就在中间的某个地方。

您可能还需要重写功能,以便首先检查好日(无错误)方案(例如,如果您预计错误的数量平均很小)。

从某种意义上讲Trie压缩数据,但如果您遇到内存问题,请尝试使用表格表示而不是对象和指针。

最后,您可以将其与bloom filters结合使用,以过滤绝对不在集合中的数字,然后使用上面的树检查其余部分。