如何实现缓存友好的动态二进制树
How to implement a cache friendly dynamic binary tree?
根据包括维基百科在内的几个来源,实现二进制树最常用的两种方法是:
- 节点和指针(或引用),其中每个节点显式地包含其子节点
- 数组其中子节点的位置由其父节点的索引隐式给定
第二个在内存使用和引用位置方面明显优越。但是,如果您希望允许从树中插入和删除,这可能会导致树不平衡。这是因为这种设计的内存使用量是树深度的指数函数。
假设您希望支持这样的插入和删除。如何实现树,使树遍历充分利用CPU缓存。
我正在考虑为节点创建一个对象池,并将它们分配到一个数组中。通过这种方式,节点将靠近在一起->因此具有良好的参考位置。
但是,如果节点的大小与缓存行的大小相同,这有意义吗
如果L1行大小为64字节,并且访问std::vector<std::uint8_t>(64)
的第一个成员,则可能会在L1缓存中包含向量的全部内容。这意味着您可以非常快速地访问任何元素。但是,如果元素的大小与缓存行大小相同,该怎么办?由于L1、L2和L3高速缓存的高速缓存行可能没有太大的不同,因此引用的局部性在这里似乎没有任何帮助。我错了吗?还能做什么?
除非你正在研究如何改进缓存访问模式的二进制树,否则我觉得这是一个XY问题——你想解决的问题是什么?为什么你认为二叉树是解决你的问题的最佳算法?预期的工作集大小是多少?
如果你正在寻找一个通用的关联存储,有多种缓存友好(其他关键词:"缓存高效"、"缓存不经意")算法,比如Judy数组,PDF对此有广泛的解释。
如果您的工作集大小足够小,并且只需要有序的项目集,那么一个简单的有序数组可能就足够了,这可能会带来另一个性能优势——分支预测。
最后,要找出最适合您的用例的方法,需要尝试并衡量不同的方法。
使用块分配器。
您有一个或几个连续的内存"池",您可以从中分配固定大小的块。它被实现为一个链表。所以分配只是
answer = head,
head = head->next,
return answer;
释放只是
tofree->next = head;
head = tofree;
如果允许多个池,当然需要编写代码来确定池,这会增加一些复杂性,但不会增加太多。它本质上是一个简单的内存分配系统。由于所有池成员在内存中都很接近,所以在小树上可以获得良好的缓存一致性。对于大树,你得聪明一点。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- std::向量与传递值的动态数组
- 在c++中用vector填充一个简单的动态数组
- C++中的动态铸造故障
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 无法在二进制文件中存储动态数组
- 为什么动态链接的二进制显示硬编码为so name
- mbed uvisor 动态加载二进制文件
- 如何用C++在windows上制作一个二进制兼容的动态库
- 如何实现缓存友好的动态二进制树
- 静态或动态链接到容器中运行的二进制文件的 C 运行时 (CRT)
- 从二进制文件中读取在结构中动态分配的数组
- 从文件读取二进制文件到动态分配的数组
- 在运行时动态更新二进制文件(可执行文件)而不停止的任何类型的方法
- 二进制 I/O 到具有二维动态数组的文件
- 在C++中使用带有二进制搜索的new动态内存分配
- 将动态链接的elf二进制文件转换为静态链接的
- c++中的动态(类型)二进制缓冲区
- 从二进制文件中读取动态内存分配的字符串(char*)
- 如何在不使用动态内存分配的情况下创建基于指针的二进制树