我目前正在从事一个嵌入式设备项目,我遇到了性能问题。分析找到了一个我想消除的 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[]kA[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) 仍然可以接受。