C++;用于多个搜索的最快数据结构 C++中的编码。我需要一个数据结构为一堆排序字符串。我将一次插入所有字符串,而不是更新它,但我会经常搜索字符串。我只需要看看结构中是否存在给定字符串。我预计名单上大约有100个字符串。 什么是更快的结构?起初我在考虑hashmap,但我在某处看到,对于如此少量的元素,对向量进行二进制搜索会更好(因为它们是经过排序的)。
除非你每秒进行数亿次搜索,否则你将无法分辨差异。 如果你一秒钟要做数亿次搜索,试试基数树。它的内存非常昂贵,但对于这个小数据集来说,这并不重要 编写之后,请对其进行分析。判断特定情况下哪种结构最快的最佳(也是唯一)方法是使用不同的数据结构对其进行实际基准测试/测量。然后选择最快的 或者换句话说:衡量你的代码比那些认为自己太聪明而无法衡量的人更有优势C++;用于多个搜索的最快数据结构 C++中的编码。我需要一个数据结构为一堆排序字符串。我将一次插入所有字符串,而不是更新它,但我会经常搜索字符串。我只需要看看结构中是否存在给定字符串。我预计名单上大约有100个字符串。 什么是更快的结构?起初我在考虑hashmap,但我在某处看到,对于如此少量的元素,对向量进行二进制搜索会更好(因为它们是经过排序的)。,c++,vector,data-structures,hashmap,C++,Vector,Data Structures,Hashmap,除非你每秒进行数亿次搜索,否则你将无法分辨差异。 如果你一秒钟要做数亿次搜索,试试基数树。它的内存非常昂贵,但对于这个小数据集来说,这并不重要 编写之后,请对其进行分析。判断特定情况下哪种结构最快的最佳(也是唯一)方法是使用不同的数据结构对其进行实际基准测试/测量。然后选择最快的 或者换句话说:衡量你的代码比那些认为自己太聪明而无法衡量的人更有优势 对于您在问题中提到的100个元素这样的小列表,使用什么结构/算法没有多大区别,因为所获得的时间可能可以忽略不计,除非您的程序经常执行搜索。使用std
对于您在问题中提到的100个元素这样的小列表,使用什么结构/算法没有多大区别,因为所获得的时间可能可以忽略不计,除非您的程序经常执行搜索。使用
std::unordered\u set
,这非常适合您的情况。如果还需要按顺序迭代,则可以使用std::set
如果在分析后发现您花费了所有的时间查询数据结构,那么现在是时候问另一个问题了(使用您将要使用的精确代码)。假设您谈论的是“全尺寸”CPUs1,通过字符串进行二进制搜索,即使只有100个元素,也可能非常慢,至少相对于其他解决方案。每次搜索可能会出现多个分支预测失误,最终可能会多次检查输入字符串中的每个字符(因为您需要在二进制搜索中的每个节点重复执行
strcmp
)
正如已经有人指出的那样,唯一真正知道的方法是衡量——但要做到这一点,你仍然需要首先能够弄清楚候选人是什么!此外,在现实场景中并不总是能够进行度量,因为可能甚至不知道这样的场景(例如,想象一下,设计一个在许多不同情况下广泛使用的库函数)
最后,了解什么可能是快速的,可以让你排除那些你知道会表现糟糕的候选者,并让你用自己的直觉仔细检查你的测试结果:如果某件事情比你预期的慢得多,那么值得检查一下为什么(编译器做了愚蠢的事情),如果事情进展得更快,那么也许是时候更新你的直觉了
因此,我将尝试实际尝试一下什么将是快速的——假设速度在这里真的很重要,您可以花一些时间验证一个复杂的解决方案。作为基线,一个简单的实现可能需要100纳秒,而一个真正优化的实现可能需要10纳秒。因此,如果你在这方面花费了10个小时的工程时间,你将不得不调用这个函数4000亿次,以赚取10个小时的回报5。当您考虑到bug风险、维护复杂性和其他开销时,您需要确保在尝试优化该函数之前,您已经多次调用该函数。这样的功能很少见,但它们确实存在
也就是说,您缺少了许多帮助设计快速解决方案所需的信息,例如:
std::string
还是const char*
还是其他什么如果“<强>(4)< /强>”,你可以接受一个(可控的)假正点2,或者“<强>(3)< /强> >你的大多数搜索将不成功,那么你应该考虑A。例如,您可以使用一个1024位(128字节)的过滤器,并使用一个60位的字符串哈希值,用6个10位函数索引到该字符串中。这使得假阳性率<1%
这样做的优点是,在散列计算之外,它独立于字符串的长度,并且不依赖于匹配行为(例如,如果字符串的公共前缀较长,则依赖于重复字符串比较的搜索速度会较慢) 如果您可以接受误报,那么您就完成了-但是如果您需要它总是正确的,但是期望大部分搜索都不成功,那么您可以将它用作一个过滤器:如果bloom过滤器返回false(通常的情况),那么您就完成了,但是如果它返回true,那么您需要再次检查下面讨论的一个始终正确的结构。因此,常见的情况很快,但总是会返回正确的答案 完全散列如果在编译时知道了100个字符串的集合,或者你可以做一些一次性的重工作来预处理字符串,那么你可以考虑一个完美的哈希。如果您有一个编译时已知的搜索集,只需将字符串插入其中,它就会输出一个哈希函数和查找表
例如,我刚刚将100个随机英语单词3输入到gperf
中,它生成了一个哈希函数,只需查看两个字符即可唯一区分每个单词,如下所示:
static unsigned int hash (const char *str, unsigned int len)
{
static unsigned char asso_values[] =
{
115, 115, 115, 115, 115, 81, 48, 1, 77, 72,
115, 38, 81, 115, 115, 0, 73, 40, 44, 115,
32, 115, 41, 14, 3, 115, 115, 30, 115, 115,
115, 115, 115, 115, 115, 115, 115, 16, 18, 4,
31, 55, 13, 74, 51, 44, 32, 20, 4, 28,
45, 4, 19, 64, 34, 0, 21, 9, 40, 70,
16, 0, 115, 115, 115, 115, 115, 115, 115, 115,
/* most of the table omitted */
};
register int hval = len;
switch (hval)
{
default:
hval += asso_values[(unsigned char)str[3]+1];
/*FALLTHROUGH*/
case 3:
case 2:
case 1:
hval += asso_values[(unsigned char)str[0]];
break;
}
return hval;
}
in_word_set: # @in_word_set
push rbx
lea eax, [rsi - 3]
xor ebx, ebx
cmp eax, 19
ja .LBB0_7
lea ecx, [rsi - 1]
mov eax, 3
cmp ecx, 3
jb .LBB0_3
movzx eax, byte ptr [rdi + 3]
movzx eax, byte ptr [rax + hash.asso_values+1]
add eax, esi
.LBB0_3:
movzx ecx, byte ptr [rdi]
movzx edx, byte ptr [rcx + hash.asso_values]
cdqe
add rax, rdx
cmp eax, 114
ja .LBB0_6
mov rbx, qword ptr [8*rax + in_word_set.wordlist]
cmp cl, byte ptr [rbx]
jne .LBB0_6
add rdi, 1
lea rsi, [rbx + 1]
call strcmp
test eax, eax
je .LBB0_7
.LBB0_6:
xor ebx, ebx
.LBB0_7:
mov rax, rbx
pop rbx
ret
现在,您的散列函数很快,并且很可能可以很好地预测(如果您不这样做的话)
/**
* Returns a canonical representation for the string object.
* <p>
* A pool of strings, initially empty, is maintained privately by the
* class <code>String</code>.
* <p>
* When the intern method is invoked, if the pool already contains a
* string equal to this <code>String</code> object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this <code>String</code> object is added to the
* pool and a reference to this <code>String</code> object is returned.
* <p>
* It follows that for any two strings <code>s</code> and <code>t</code>,
* <code>s.intern() == t.intern()</code> is <code>true</code>
* if and only if <code>s.equals(t)</code> is <code>true</code>.
* <p>
* All literal strings and string-valued constant expressions are
* interned. String literals are defined in section 3.10.5 of the
* <cite>The Java™ Language Specification</cite>.
*
* @return a string that has the same contents as this string, but is
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
Java_java_lang_String_intern(JNIEnv *env, jobject this)
{
return JVM_InternString(env, this);
}
/*
* java.lang.String
*/
JNIEXPORT jstring JNICALL
JVM_InternString(JNIEnv *env, jstring str);
// String support ///////////////////////////////////////////////////////////////////////////
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))
JVMWrapper("JVM_InternString");
JvmtiVMObjectAllocEventCollector oam;
if (str == NULL) return NULL;
oop string = JNIHandles::resolve_non_null(str);
oop result = StringTable::intern(string, CHECK_NULL);
return (jstring) JNIHandles::make_local(env, result);
JVM_END
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = java_lang_String::hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop string = the_table()->lookup(index, name, len, hashValue);
// Found
if (string != NULL) return string;
// Otherwise, add to symbol to table
return the_table()->basic_add(index, string_or_null, name, len,
hashValue, CHECK_NULL);
}
oop StringTable::lookup(int index, jchar* name,
int len, unsigned int hash) {
for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) {
if (l->hash() == hash) {
if (java_lang_String::equals(l->literal(), name, len)) {
return l->literal();
}
}
}
return NULL;
}
String* myStrings[256];
String* myStrings[256][256][256];
char charToSlot[256];
String* myStrings[3];
char charToSlot[256];
String* myStrings[26];
char charToSlot[256];
String* myStrings[26][26][26];
char charToSlot[256];
String**** myStrings;
String* myStrings[30][256][256]...
String* myStrings[8];
String* myStrings[8][8][8][8]...
typedef struct {
char book_name[30];
char book_description[61];
char book_categories[9];
int book_code;
} my_book_t;
// 160000 size, 10 index field slot
bin_array_t *all_books = bin_array_create(160000, 10);
if (bin_add_index(all_books, my_book_t, book_name, __def_cstr_sorted_cmp_func__)
&& bin_add_index(all_books, my_book_t, book_categories, __def_cstr_sorted_cmp_func__)
&& bin_add_index(all_books, my_book_t, book_code, __def_int_sorted_cmp_func__)
) {
my_book_t *bk = malloc(sizeof(my_book_t));
strcpy(bk->book_name, "The Duck Story"));
....
...
bin_array_push(all_books, bk );
int data_search = 100;
bin_array_rs *bk_rs= (my_book_t*) ba_search_eq(all_books, my_book_t,
book_code, &data_search);
my_book_t **bks = (my_book_t**)bk_rs->ptrs; // Convert to pointer array
// Loop it
for (i = 0; i < bk_rs->size; i++) {
address_t *add = bks[i];
....
}
// Join Solution
bin_array_rs *bk_rs=bin_intersect_rs(
bin_intersect_rs(ba_search_gt(...), ba_search_lt(...), true),
bin_intersect_rs(ba_search_gt(...), ba_search_lt(....), true),
true);
// Union Solution
bin_array_rs *bk_rs= bin_union_rs(
bin_union_rs(ba_search_gt(...), ba_search_lt(...), true),
bin_union_rs(ba_search_gt(...), ba_search_lt(....), true),
true);