在小型MCU上优化稀疏阵列中的元素查找

Optimizing Element Lookup in Sparse Array on small MCU

提问人:nowox 提问时间:11/15/2023 更新时间:11/15/2023 访问量:86

问:

我正在开发一个应用程序,该应用程序涉及管理分布在大小为 M 的数组中的 N 个 Element 实例,其中 N << M(N 比 M 小得多)。这些元素可以通过它们的索引进行访问,它们在数组中的分布在构建时是已知的,但没有遵循特定的模式。

主要目标:我寻求一种算法,该算法允许通过索引对元素进行有效(时间)检索,同时还要注意空间限制。理想情况下,我希望避免分配 O(M) 空间,这虽然会导致 O(1) 时间复杂度,但对于我的应用程序来说是不可行的。

上下文:此任务是为工作频率为 50 MHz 且没有浮点单元 (FPU) 的 16 位微控制器单元 (MCU) 开发 CanOpen 从站堆栈的一部分。传统的哈希表似乎是一个显而易见的解决方案,但由于 MCU 的局限性,它并不适合。

当前方法:我正在考虑使用简化的 Murmur 哈希函数的开放式寻址哈希表。下面是初步函数:

const int A = 16;
const int B = 0x45d9f3b;
const int C = B;

unsigned int hash(unsigned int x) {
    x = ((x >> A) ^ x) * B;
    x = ((x >> A) ^ x) * C;
    x = (x >> A) ^ x;
    return x;
}

我计划尝试使用不同的 A、B 和 C 值,以最大程度地减少访问时间并减少冲突。最终,使用自动化脚本运行构建时间以找到最佳的 A、B、C 常量。

问题:考虑到限制,这种方法是否可行,或者是否有更有效的算法或方法更适合这种情况?我对其他建议持开放态度,包括使用二叉搜索的可能性。

其他信息

此设置是运行实时应用程序的小型MCU上的CANopen从站堆栈的一部分。虽然 CanOpen 使用 16 位对象字典,但我的应用程序只需要 100-200 个对象。关键是尽量减少每个对象的访问时间。

我的处理能力有限,MCU 上没有 FPU。空间效率与时间效率同样重要。

C++ 算法 优化 搜索

评论

1赞 ChrisB 11/15/2023
您是否评估过二进制搜索是否适用于您的用例?因为如果是这样,我会同意的。与任何具有最坏情况空间要求的无冲突散列方案相比,它具有更高的内存效率(实际上为零开销),并且更容易实现。O(n)
0赞 nowox 11/15/2023
@ChrisB 对 100-1000 个条目进行二进制搜索将是 8-10 次比较,因此需要 4-5 次管道刷新,即 30-50 个周期才能找到值。
0赞 user3386109 11/15/2023
@nowox 计算该哈希函数需要多少个周期?然后是房间里的大象:解决开放寻址平均需要多少个周期?
2赞 ChrisB 11/15/2023
@nowox:在不知道你的限制的情况下,我会把它解释为“它会起作用,但似乎很昂贵”。我的建议是:顺其自然,如果它成为一个问题,就研究完美的哈希。
0赞 nowox 11/15/2023
@user3386109 这是我需要弄清楚的好问题。我会说最多 10-13 个周期。

答:

1赞 btilly 11/15/2023 #1

如果没有关于阵列结构的进一步信息,这是不可能的。

如果您有对象,则可以对数组进行编码。如果不发送那么多信号,就无法对所有可能的数组进行编码。这需要比特。这是数据。100100^mm * log_2(100)O(m)

使用有关数组的其他数据,可以减少要编码的可能数组的数量,从而减少数据存储。但是,试图隐藏哈希函数背后的复杂性并不能使你摆脱鸽子洞原则——如果不使用足够的数据来创建不同的可能信号,你就无法区分不同的数组。这需要最少的位。xxlog_2(x)

如果你能负担得起一个字节数组,我会这样做。否则,你要么会发现一些关于数组如何生成的东西,要么你将不得不将你的目标更改为可行的东西。m

3赞 ChrisB 11/15/2023 #2

考虑到这些限制,这种方法是否可行,或者是否有更有效的算法或方法更适合这种情况?

您描述的方法对于查找具有良好平均查找时间的哈希函数是可行的。

但我强烈建议使用您拥有的实际内存大小(但未在问题中指定)对碰撞概率进行一些简单的餐巾纸数学运算(为了简单起见,您可以假设哈希函数完美分布)来了解最坏情况

你提到你有实时约束,所以我有一种感觉,最坏的情况时间(从碰撞链的最大长度得出)可能不让你满意。您可以让生成时脚本循环,直到它找到解决方案,但(取决于您的约束)可能并不总是有一个,因此在极少数情况下,您的生成可能会失败。

另一种方法是使用完美的哈希函数,它可以为您提供有保证的最坏情况,因为它没有冲突。

评论

0赞 btilly 11/15/2023
您尚未解决关键问题,即需要多少空间才能完成这项工作。答案是它会是.O(m)
1赞 ChrisB 11/15/2023
@billy:我建议的完美散列方法可以在 .这是一个相当容易阅读的证明(在 10.5.2 下)。我没有对问题中描述的 Murmur 哈希函数系列的抗碰撞性进行任何分析。如果你有(导致你声称使用这个哈希函数有一个有保证的解决方案),请展示你的作品。O(n)O(m)
0赞 Red.Wave 11/15/2023
由于元素在编译时是已知的,因此有效哈希的空间复杂度将为 O(N),运行时复杂度应为 O(log M)。