13 个版本
新版本 0.4.1 | 2024年8月19日 |
---|---|
0.4.0 | 2024年5月24日 |
0.3.8 | 2024年2月17日 |
0.3.6 | 2023年8月12日 |
0.1.0 | 2023年7月4日 |
#401 在 数据结构 中排名
每月 下载 355 次
在 物化视图 中使用
135KB
2.5K SLoC
indexset
一个纯 Rust 动态有序统计 b-tree。
该软件包实现了一种紧凑的集合数据结构,它保留其元素的排序顺序,并允许通过值或排序顺序位置查找条目。
此外,它(在大多数情况下)是 stdlib BTree 的直接替换品。
背景
该项目受到了 indexmap
和 python 的 sortedcontainers
的强烈启发。
与两者不同的是
indexmap
是一个提供数值查找的哈希表,但在删除的情况下不会保持顺序,而indexset
是一个始终保持顺序的 BTree,无论执行哪种突变操作。sortecontainers
在精神上类似,但使用不同的算法来平衡树,并且依赖于堆进行数值查找。
indexset
提供以下功能
- 与 vec 一样快速迭代。
- 零间接。
- 按位置和范围查找。
- 分配最少的内存。
select
(按位置查找)和rank
(按值查找)操作在接近常数时间内完成。
性能
BTreeSet
和 BTreeMap
从其构建方式直接推导出一些性能事实,大致为
一个二级 B-Tree,其中使用 Fenwick 树作为数值查找的低成本索引
- 迭代非常快,因为它继承了 vec 的迭代结构。
- 在最佳情况下,插入和删除操作是常数时间,在最坏情况下,在节点大小上是对数时间
- 查找非常快,并且仅依赖于少量数据的两次二分搜索。
基准测试
运行 cargo bench
并自行查看。
在一台最低配置的 M1 Macbook Pro 上,我得到了以下数据
插入 100k 随机 usize
stdlib::collections::BTreeSet.insert(i)
: 8.25msindexset::BTreeSet.insert(i)
: 17.3ms
检查每个100k随机usize整数是否存在
stdlib::collections::BTreeSet.contains(i)
: 7.5msindexset::BTreeSet.contains(i)
: 6.8ms
获取所有100k个i-th元素
stdlib::collections::BTreeSet.iter.nth(i)
: 13.28s yes, seconds!indexset::BTreeSet.get_index(i)
: 3.93ms
遍历所有100k个元素并将它们收集到一个vec中
Vec::from_iter(stdlib::collections::BTreeSet.iter())
: 227.28usVec::from_iter(indexset::BTreeSet.iter())
: 123.21.us
是的。
获取第i个元素比stdlib的btree快3400倍,contains
快10%,迭代快两倍,但插入速度减半。
如果你的使用场景是std::collections::BTreeSet
和BTreeMap
更侧重于读取,或者你确实需要按排序顺序位置索引,那么检查这个indexset
可能是有价值的。
局限性
BTreeMap
比BTreeSet
更不成熟。这个crate已经针对更精简的BTreeSet
进行了优化。- 这是**beta**级别的软件,所以请自行承担使用风险。我对每个迭代器的实现(尽管所有内容都有测试)并不完全确定。
- 还有相当多的实用特性尚未实现。
命名
这个库叫做indexset
,因为基本数据结构是BTreeSet
。BTreeMap
是一个具有Pair<K, V>
项类型的BTreeSet
。
变更日志
依赖项
~0.4–1MB
~22K SLoC