确定字符是否属于一组已知字符的最快方法C ++

时间:2015-03-16 00:58:47

标签: c++ c++11 stl containers unordered-set

鉴于任何字符,我最快的方法是确定该字符是否属于已知字符的集合(不是容器类型)。

换句话说,实施条件的最快捷方式是什么:
    char c = 'a';
    if(c == ch1 || c == ch2 || c == ch3 ...) // Do something...

是否存在STL容器(我认为它可能是unordered_set?)我可以将该字符作为键传递给它,如果该键存在则它将返回true?

任何具有O(1)查找时间的东西都适用于我。

6 个答案:

答案 0 :(得分:10)

我进一步编写了两个版本,一个基于查找数组,另一个使用底层哈希。

class CharLookup {
public:
  CharLookup(const std::string & set) : lookup(*std::max_element(set.begin(), set.end()) + 1) {
    for ( auto c : set) lookup[c] = true;
  }
  inline bool has(const unsigned char c) const {
    return c > lookup.size() ? false : lookup[c];
  }
private:
  std::vector<bool> lookup;
};

class CharSet {
public:
  CharSet(const std::string & cset) {
    for ( auto c : cset) set.insert(c);
  }
  inline bool has(const unsigned char c) const {
    return set.contains(c);
  }
private:
  QSet<unsigned char> set;
};

然后写了一个小基准,为了比较添加了几个容器。越低越好,数据点是&#34;字符集大小/文本大小&#34;:

enter image description here

似乎对于短字符集和文本,std::string::find_first_of最快,甚至比使用查找数组更快,但随着测试大小的增加而迅速缩小。 std::vector<bool>似乎是&#34;黄金意思&#34;,QBitArray可能有一些不同的实现,因为它随着测试大小的增加而提前,最大的测试QVector<bool>最快,大概是因为它没有比特访问的开销。两个哈希集是关闭的,交易位置,最后一个,最少的是std::set

使用MinGW 4.9.1 x32和-O3在i7-3770k Win7 x64盒子上测试。

答案 1 :(得分:7)

您可以创建一个布尔数组,并为所需集中的每个字符分配值true。例如,如果您想要的集合包含'a', 'd', 'e'

bool array[256] = {false};
array['a'] = true;
array['d'] = true;
array['e'] = true;

然后你可以检查一个角色c

if (array[c]) ... 

我们也可以为此目的使用bitset:

std::bitset<256> b;
b.set('a');
b.set('d');
b.set('e');

并检查为:

if (b.test(c)) ...

答案 2 :(得分:1)

通常,这种测试不是孤立的,即你不是

if(c==ch1 || c==ch2 || c=ch3 ) {... }

但是

if(c==ch1 || c==ch2 || c=ch3 ) {... }
else if(c==ch4 || c==ch5 || c=ch6 ) {... }    
else if(c==ch7 || c==ch8 || c=ch9 ) {... }

if(c==ch4 || c==ch6 || c=ch7 ) {... }

在这种情况下,我建立一个包含所需信息的角色特征数组。

// First 2 bits contains the "type" of the character
static const unsigned char CHAR_TYPE_BITS = 3;
static const unsigned char CHAR_TYPE_A = 0;  
static const unsigned char CHAR_TYPE_B = 1;
static const unsigned char CHAR_TYPE_C = 2;
// Bit 3 contains whether the character is magic
static const unsigned char CHAR_IS_MAGIC = 4;

static const unsigned char[256] char_traits = {
  ...,
  CHAR_TYPE_A, CHAR_TYPE_B | CHAR_IS_MAGIC ...
  ...
}

static inline unsigned char get_character_type(char c) {
  return char_traits[(unsigned char)c] & CHAR_TYPE_BITS;
}

static inline boolean is_character_magic(char c) {
 return (char_traits[(unsigned char)c] & CHAR_IS_MAGIC) == CHAR_IS_MAGIC;
}

现在您的条件变为

switch(get_character_type(c)) { 
 case CHAR_TYPE_A:
    ...
    break;
 case CHAR_TYPE_B:
    ...
    break;
 case CHAR_TYPE_C:
    ...
    break;
}

if(is_character_magic(c)) {
  ...
}

我通常会将char_traits变量提取到自己的include中,并生成包含使用简单程序的变量。这可以让事情变得容易改变。

答案 3 :(得分:1)

保持简单。

static const char my_chars[] = { 'a', 'b', 'c' };
if (std::find(std::begin(my_chars), std::end(my_chars), char_to_test))

查找是线性的,但这并不能说明整个故事。其他数据结构可以提供常量查找,但常量可以高于最大“线性”值!如果增加n的搜索时间是O(1)=(100,100,100)和O(n)=(10,20,30),那么你可以看到O(n)比O(1)更快这些小n。

由于只有少量字符,如果简单的线性搜索测量速度比某些真实代码中的替代字符慢,我会感到非常惊讶。

如果确保对数组进行了排序,则还可以尝试std::binary_search。我不知道对于少数值来说它会更快还是更慢。

一如既往,要确保措施。

答案 4 :(得分:0)

您是否尝试针对要比较的字符串检查单个字符?

<强> std::string::find_first_of()

答案 5 :(得分:0)

这样的函数在 C 和 C++ 中可用。我想这也是一个相对较快的功能。我已经包含了一个 C++ 示例应用程序,它必须检测一个字符是否是一个分隔符。

#include <cstring>

bool is_separator(char c)
{
    return std::strchr(" \f\t\v\r\n\\+-=()", c); // this includes \0!
}