我目前正在从事一个嵌入式设备项目,我遇到了性能问题。分析找到了一个我想消除的 O(N) 操作。
我基本上有两个数组int A[N]
和short B[N]
. 中的条目A
是唯一的,并由外部约束排序。最常见的操作是检查特定值是否a
出现在A[]
. 不太常见但仍然常见的是对 的元素进行更改A[]
。新值与之前的值无关。
由于最常见的操作是查找,这就是B[]
出现的地方。它是 中的索引的排序数组A[]
,因此A[B[i]] < A[B[j]]
当且仅当i<j
。这意味着我可以A
使用二进制搜索找到值。
当然,当我更新时A[k]
,我必须找到k
并B
移动它到一个新的位置,以保持搜索顺序。由于我知道 的新旧值A[k]
,因此这只是 的新旧位置之间的memmove()
一个子集。这是我需要修复的 O(N) 操作;由于 的新旧值基本上是随机的,我平均移动大约N/2 N/3 个元素。B[]
k
A[k]
我研究了std::make_heap
用作[](int i, int j) { return A[i] < A[j]; }
谓词。在那种情况下,我可以很容易地B[0]
指出 的最小元素A
,并且更新B
现在是一个廉价的 O(log N) 重新平衡操作。但是,我通常不需要 A 的最小值,我需要查找是否存在任何给定值。现在这是一个 O(N log N) 搜索B
。(我的 N 个元素中有一半位于堆深度 log N,四分之一位于 (log N)-1 等),这与直接在A
.
考虑到std::set
有 O(log N) 的插入和查找,我想说应该有可能在这里获得相同的性能来进行更新和查找。但是我该怎么做呢?我需要另一个订单B
吗?不同的类型?
B
目前是short [N]
因为A
和B
一起大约是我的 CPU 缓存的大小,而我的主内存要慢很多。从 6*N 到 8*N 字节不是很好,但如果我的查找和更新都达到 O(log N) 仍然可以接受。