用于查找字符串差异的位操作

时间:2009-02-17 14:50:20

标签: c++ string

我的以下字符串试图找出两个字符串之间的区别。 但是它迭代字符串的长度非常慢:

#include <string>
#include <vector>
#include <iostream>
using namespace std;


int hd(string s1, string s2) {
    // hd stands for "Hamming Distance"
    int dif = 0;

    for (unsigned i = 0; i < s1.size(); i++ ) {
        string b1 = s1.substr(i,1);
        string b2 = s2.substr(i,1);

        if (b1 != b2) {
            dif++;
        }
    }  

    return dif;
}

int main() {

    string string1 = "AAAAA";
    string string2 = "ATATT";
    string string3 = "AAAAA";

    int theHD12 = hd(string1,string2);
    cout << theHD12 << endl;

    int theHD13 = hd(string1,string3);
    cout << theHD13 << endl;
}

有没有快速替代方案呢? 在Perl中,我们可以采用以下方法:

sub hd {
    return ($_[0] ^ $_[1]) =~ tr/\001-\255//;
}

比迭代位置快2倍。

我想知道它在C ++中的含义是什么?

6 个答案:

答案 0 :(得分:12)

尝试通过以下方式替换for循环:

for (unsigned i = 0; i < s1.size(); i++ ) {
    if (b1[i] != b2[i]) {
            dif++;
    }
}  

这应该快得多,因为没有创建新的字符串。

答案 1 :(得分:9)

STL乐趣:

#include <numeric>    //inner_product
#include <functional> //plus, equal_to, not2
#include <string>   
#include <stdexcept>

unsigned int 
hd(const std::string& s1, const std::string& s2)
{
    // TODO: What should we do if s1.size() != s2.size()?
    if (s1.size() != s2.size()){
      throw std::invalid_argument(
          "Strings passed to hd() must have the same lenght"
      );
    }

    return std::inner_product(
        s1.begin(), s1.end(), s2.begin(), 
        0, std::plus<unsigned int>(),
        std::not2(std::equal_to<std::string::value_type>())
    );
}

答案 2 :(得分:4)

使用迭代器:

int GetHammingDistance(const std::string &a, const std::string &b)
{
    // Hamming distance is not defined for strings of different lengths.
    ASSERT(a.length() == b.length());

    std::string::const_iterator a_it = a.begin();
    std::string::const_iterator b_it = b.begin();

    std::string::const_iterator a_end = a.end();
    std::string::const_iterator b_end = b.end();

    int distance = 0;
    while (a_it != a_end && b_it != b_end)
    {
        if (*a_it != *b_it) ++distance;
        ++a_it; ++b_it;
    }

    return distance;
}

答案 3 :(得分:3)

选择1:修改原始代码以尽可能高效。

int hd(string const& s1, string const& s2)
{
    // hd stands for "Hamming Distance"
    int dif = 0;

    for (std::string::size_type i = 0; i < s1.size(); i++ )
    {
        char b1 = s1[i];
        char b2 = s2[i];

        dif += (b1 != b2)?1:0;
    }  

    return dif;
}

第二个选项使用一些STL算法来完成繁重的工作。

struct HammingFunc
{
    inline int operator()(char s1,char s2)
    {
        return s1 == s2?0:1;
    }
};

int hd(string const& s1, string const& s2)
{
    int diff = std::inner_product(s1.begin(),s1.end(),
                                  s2.begin(),
                                  0,
                                  std::plus<int>(),HammingFunc()
                                 );
    return diff;
}

答案 4 :(得分:2)

一些明显的观点可能会让它更快:

  1. 将字符串作为const引用传递,而不是按值传递
  2. 使用索引运算符[]获取字符,而不是方法调用
  3. 上进行优化编译

答案 5 :(得分:2)

您使用字符串。

如此处所述 The hunt for the fastest Hamming Distance C implementation 如果你可以使用char *我的经验得出结论 Gcc 4.7.2 Intel Xeon X5650 最快的通用汉明距离计算功能> strings(char数组)是:

// na = length of both strings
unsigned int HammingDistance(const char* a, unsigned int na, const char* b) {

    unsigned int num_mismatches = 0;
    while (na) {
        if (*a != *b)
            ++num_mismatches;

        --na;
        ++a;
        ++b;
    }

    return num_mismatches;
}

如果你的问题允许你设置一个上限距离,这样你就不用考虑更远的距离了,这个限制总是小于字符串的长度,上面的例子可以很好地优化到:

// na = length of both strings, dist must always be < na
unsigned int HammingDistance(const char* const a, const unsigned int na, const char* const b, const unsigned int dist) {

    unsigned int i = 0, num_mismatches = 0;

    while(i <= dist)
    {
        if (a[i] != b[i])
            ++num_mismatches;

        ++i;
    }

    while(num_mismatches <= dist && i < na)
    {
        if (a[i] != b[i])
            ++num_mismatches;

        ++i;
    }

    return num_mismatches;
}

我不确定const是否对速度有任何影响,但无论如何我都会使用它......