我有一个C数组,很少(几乎从未)更新过:
unsigned long user_values[8];
我希望能够进行大量快速查找(在慢速机器上每秒数百次),检查数组中是否有值,如果是,则获取其索引。几乎所有的时候,这个查找都无法在数组中找到该项。
通常,我会保持数组排序,并使用二进制搜索,但我不确定二进制搜索在非常小的数据集上的效率。有没有更有效的方法来执行此查找,因为它的已知大小很小?
答案 0 :(得分:3)
我建议使用小哈希来立即检测大多数故障。像这样:
#define HASH(x) ((x) & 0xff) // This can be improved if needed
uint8_t possible[256];
void initHash()
{
int i;
memset(possible, 0, sizeof(possible));
for (i=0;i<8;i++)
possible[HASH(user_values[i])] = 1;
}
int find(unsigned long val)
{
// Rule out most failures with a quick test.
if (!possible[HASH(val)])
return -1;
// Now use either binary or linear search.
...
}
请注意,在256个插槽哈希表中设置最多8个插槽,您将立即清除31/32或97%的故障。有三种明显的方法可以改善这种情况:
答案 1 :(得分:1)
你想要多少加速?除非你的集合(数组)中有一些可利用的模式,只需8次检查,否则无论如何都会获得最小的收益。编译器通常非常擅长优化这类事情。我发现使用一些gcc编译,在我的for循环中使用指针可以给我几个百分点。展开循环,因为你知道静态8偏移可能值几个百分点(也可能不是)。
这是一个假设的可利用数据模式。如果您的集合/矢量/列表/数组/调用它们将倾向于聚类并且您要测试的候选范围均匀分布在0x00000000到0xFFFFFFFF范围内,那么您可能获得很少有你的矢量预分类,只是测试少于第一个或大于最后一个,这将是2个测试,可能通常失败,当它没有时,转移到列表中的线性搜索。但是这种事情实际上取决于各种比例(窗口有多宽?预分类增加多少开销等等)。只针对您的真实世界数据进行测试即可。
并且总是存在真正的危险,可利用的模式在正常情况下提供20%的速度时,在你的假设被违反的边缘情况下表现得非常糟糕,并且会受到数量级的伤害。
答案 2 :(得分:1)
switch
-case
jump table有一些技巧,但它要求编译器利用它,在您的特定情况下可能会或可能不会发生。而不是将这些值保留在数组中(因为你写的值几乎从未改变),将它们字面上称为标签:
#define NOT_FOUND -1
int index = NOT_FOUND; // or any other way to mark that number is not found
switch (val)
{
case 0x00000000UL : // replace with array values
index = 0; break;
case 0x00000001UL :
index = 1; break;
case 0x00000002UL :
index = 2; break;
// ...
};
唯一的缺点是数字现在已经修复了#34;在编译时。因此,要更新它们,您需要重新编译整个程序,这可能是不可接受的(?)。
答案 3 :(得分:1)
该程序进行二分搜索和线性搜索(很多次,因此可以很容易地定时)。在OP的条件下,通常找不到搜索值,线性搜索大约需要二进制搜索的两倍。它需要3次迭代的二分搜索才能将8个元素减少到1,但是线性搜索的8次迭代。我使用unsigned int
而不是unsigned long
。
#include <stdio.h>
#include <time.h>
#define ARRLEN 8
#define LOOPS 0x7FFFFF
unsigned user_values[ARRLEN] = { 1, 234, 8124, 8335, 10234, 11285, 637774, 788277 };
int main (int argc, char *argv[]) {
unsigned val;
int bot, top, mid, loop;
clock_t start, elap;
if (argc < 2) return 1;
if (sscanf (argv[1], "%u", &val) != 1) return 1;
// binary search
printf ("Binary search for %u: ", val);
start = clock();
for (loop=0; loop!=LOOPS; loop++) {
bot = 0;
top = ARRLEN;
while (top-bot > 1) {
mid = ((top + bot) >> 1);
if (user_values[mid] <= val)
bot = mid;
else top = mid;
}
}
elap = clock() - start;
if (user_values[bot] == val)
printf ("found");
else printf ("not found");
printf (" in count %u\n", (unsigned)elap);
// linear search
printf ("Linear search for %u: ", val);
start = clock();
for (loop=0; loop!=LOOPS; loop++) {
for (bot=0; bot<ARRLEN; bot ++)
if (user_values[bot] == val)
break;
}
elap = clock() - start;
if (bot<ARRLEN)
printf ("found");
else printf ("not found");
printf (" in count %u\n", (unsigned)elap);
return 0;
}