我的数据结构是一个链的列表。一个块包含31个4字节元素和一个指向下一个块的4字节指针或NULL(总结为每块128字节)。我不时添加元素。如果最后一个块已满,我通过指针添加另一个块。
一个目标是使用尽可能少的内存(=块)并且在块中的两个元素之间没有空闲空间。
此设置已修复。所有代码都在带有NEON管道的32位ARM Cortex-A8 CPU上运行。
的问题: 的 如何尽快在该数据结构中找到特定元素?
方法(现在): 我使用排序块和二进制搜索来检查元素(4字节中的9位是搜索条件)。如果所需元素不在当前块中,则跳转到下一个块。如果元素不在最后一个块中并且最后一个块尚未满,则使用二进制搜索的结果插入新元素(如果需要,我在此块中使用memmove创建空间)。因此,所有块总是排序。
你有想法让它更快吗? 这就是我现在搜索的方式:(q-> getPosition()是一个内联函数,只通过“& bitmask”从元素中提取9位位置)
do
{
// binary search algorithm (bsearch)
// from http://www.google.com/codesearch/
// p?hl=en#qoCVjtE_vOw/gcc4/trunk/gcc-
// 4.4.3/libiberty/bsearch.c&q=bsearch&sa=N&cd=2&ct=rc
base = &(block->points[0]);
if (block->next == NULL)
{
pointsInBlock = pointsInLastBlock;
stop = true;
}
else
{
block = block->next;
}
for (lim = pointsInBlock; lim != 0; lim >>= 1)
{
q = base + (lim >> 1);
cmp = quantizedPosition - q->getPosition();
if (cmp > 0)
{
// quantizedPosition > q: move right
base = q + 1;
lim--;
}
else if (cmp == 0)
{
// We found the QuantPoint
*outQuantPoint = q;
return true;
}
// else move left
}
}
while (!stop);
答案 0 :(得分:2)
由于大部分时间都花在块内搜索中,因此需要尽可能快。由于元素的数量是固定的,您可以完全展开该循环,如:
if (key < a[16]){
if (key < a[8]){
...
}
else { // key >= a[8] && key < a[16]
...
}
}
else { // key >= a[16]
if (key < a[24]){
...
}
else { // key >= a[24]
...
}
}
研究生成的汇编语言并在调试器中单步执行,以确保编译器为您提供良好的代码。
你可能想写一个小程序来打印上面的代码,因为很难手工编写,或者可能用宏生成它。
ADDED:刚刚注意到你的9位搜索条件。在这种情况下,只需预先分配512个4字节字的数组,然后直接对其进行索引。这是最快,最少的代码。
还添加:如果你需要保留块结构,还有另一种方法可以进行展开的二进制搜索。这是Jon Bentley方法:
i = 0;
if (key >= a[i+16]) i += 16;
if (key >= a[i+ 8]) i += 8;
if (key >= a[i+ 4]) i += 4;
if (key >= a[i+ 2]) i += 2;
if (i < 30 && key >= a[i+ 1]) i += 1; // this excludes 31
if (key == a[i]) // then key is found
这比上面的if-tree慢,因为操纵i
,但代码可能少得多。
答案 1 :(得分:1)
令每个块中的元素数量为m,列表中当前的块总数为n。那么你算法的当前时间复杂度是O(n log m)。
如果在将元素添加到块中后无法移动元素,那么我认为您在时间复杂度方面可以做得比您已经做的更好。 (您可以跟踪块中的最大和最小元素,如果元素不在此范围内,则跳过块。但这不会给您带来太大的收益。这也会浪费空间跟踪最小值和每个块的最大值)
如果您能够在插入元素时花费时间并且可以将元素从一个块移动到另一个块,那么这是一个时间复杂度为O(log(mn))的方案。
基本上,您将所有元素按排序顺序排列。当必须插入新元素时,跨块边界进行二进制搜索并将其插入正确的位置,移动元素以创建空间。这将在插入元素时导致O(nm)时间,但在找到元素时会导致O(log(mn))。
答案 2 :(得分:1)
如果元素的搜索条件是固定的,则最好将搜索移动到单独的索引结构中,因为您通过搜索条件区分的元素的最大数量仅为2 ^ 9 = 512个索引,因此最大值搜索索引的大小为(2 + 4)* 512 = 3072,但如果需要,你肯定可以使用其他静态的,节省一些内存。现在,想象它是一个512对&lt; 9位索引,直接地址&gt;的字段,应该非常快(分别只有一个NULL检查和解引用调用)。
通常,您的问题的答案还取决于您希望在结构上执行的其他操作以及每个操作的频率(包括搜索能力)。如果您只想搜索(9位) - >添加/修改/读取,您的块结构将无用。 你可以在这里写下它们,也许可以添加你使用的语言。
编辑3: 我只是注意到你不能改变块的大小。但是您的搜索仅仅是为了效率原因,还是您需要列表的元素是唯一的(通过这9位)?