给定一组字符串,比如"String1", "String2",..., "StringN"
,C ++中确定(返回true
或false
)的最有效方式是否匹配任何字符串string s
上面的字符串中的字符串?
可以将Boost.Regex用于此任务吗?
答案 0 :(得分:8)
std::unordered_set
将提供最有效的查询(摊销的常数时间)。
#include <unordered_set>
#include <string>
#include <cassert>
int main() {
std::unordered_set<std::string> s = {"Hello", "Goodbye", "Good morning"};
assert(s.find("Goodbye") != s.end());
assert(s.find("Good afternoon") == s.end());
return 0;
}
答案 1 :(得分:3)
您可以将所有字符串放在std::set中,然后检查该字符串是否在集合中。
答案 2 :(得分:2)
另一种方法是构造一个N-ary树来存储所有字符串。
节点看起来像:
struct Node {
Node* children[256]; // Or reduce to correct accepted char
bool isAWord; // true when the letters from the root forms a word
}
因此,使用"String1"
,"String10"
,"String2"
,"StringN"
,树是:
Root
|
[S]
|
[t]
|
[r]
|
[i]
|
[n]
|
[g]
/ | \
[1*] [2*] [N*]
|
[0*]
获得树后,查看字符串是否匹配 搜索复杂度:要搜索的字符串的大小。
答案 3 :(得分:2)
在您经常需要执行这些检查的某些情况下,可以从Interning获得出色的性能提升。
实习仍然需要我们有一些字符串查找数据结构,例如树或哈希表。但是,我们很少进行这些繁重的查找:具体而言,只有当一些原始文本输入从环境到达我们的软件系统时,我们才会这样做。
那时,我们将输入文本作为字符串和实习生:在现有的字符串集中查找,并将其转换为原子。原子是一小部分数据,通常是单字数量,例如机器指针。如果字符串不存在,则实习函数会为我们提供一个新的唯一原子。否则,它为我们提供了之前为该字符串提供的相同原子。
一旦我们将输入字符串插入到原子中,我们总是使用原子。因此,我们不是比较两个字符串是否相同,而是比较两个原子是否相同,这是一个“快速”单字比较操作。 (当我们需要以可读的方式打印原子时,我们仍然使用字符串:再次在我们的系统和外部世界之间的边界)。
实习来自Lisp:在Lisp中,符号是原子。在原始源代码中,它们是文本的,因此当代码被读入内存时,符号名称被插入以生成原子,这些原子基本上是指向符号对象的指针。
在其他地方进行实习,例如X Window系统(XInternAtom
功能):
Atom XInternAtom(Display *display, char *atom_name, Bool only_if_exists)
并且在Microsoft Windows API中未使用术语“实习生”,但该函数返回称为ATOM
:Lisp术语的东西。实习的内容不是简单的字符串,而是“阶级”结构:
ATOM WINAPI RegisterClass(const WNDCLASS *lpWndClass);
在这两个系统中,这些原子是系统范围的(在X的情况下是服务器范围的),并且可以比较它们所代表的对象的相等性。在Windows中,如果您有两个相等的ATOM
值,则它们是同一个类。
Flyweight Design Pattern一书中的GoF本质上是对实习的重新发明,扩展到字符串以外的结构(如上面的Win32 API中的WNDCLASS
);所以如果你想把这个想法“卖”给你的老板,你可以从这个角度来看待它。
答案 4 :(得分:1)
作为替代方案,您可以定义字符数组或字符串的有序数组,并使用标准算法std :: binary_search,std :: lower_bound,std :: upper_bound或std :: equal_range来检查目标字符串是否存在于阵列。
我将使用此处已显示的示例。
#include <algorithm>
#include <iterator>
#include <string>
#include <iostream>
#include <iomanip>
int main()
{
const char * s[] = { "Good morning", "Goodbye", "Hello" };
std::cout << std::boolalpha
<< std::binary_search( std::begin( s ), std::end( s ), std::string( "Goodbye" ) )
<< std::endl;
std::cout << std::boolalpha
<< std::binary_search( std::begin( s ), std::end( s ), std::string( "Good afternoon" ) )
<< std::endl;
return 0;
}
答案 5 :(得分:0)
假设字符串不是完全随机的并且我有共同的前缀,使用Trie可能更有效:最初构建数据结构可能比创建其他容器更昂贵但是如果有很多查询这对弦组来说可以得到回报。主要缺点是标准C ++库中没有trie实现。