15个不稳定版本 (3个破坏性更新)
0.4.0 |
|
---|---|
0.3.3 | 2024年1月5日 |
0.3.2 | 2023年4月19日 |
0.2.2 | 2023年4月10日 |
0.0.6 | 2022年12月29日 |
在数据结构中排名#731
120KB
2.5K SLoC
range_bounds_map
这个crate已被重命名为nodit
这个crate从range_bounds_map
重命名为discrete_range_map
,现在名为nodit
,因为旧名称已不准确。请切换到nodit
crate,因为这个crate将不再接收更新。
旧版自述文件
这个crate提供了RangeBoundsMap
和RangeBoundsSet
,基于BTreeMap
存储非重叠区间的数据结构。
使用Range
的示例
use range_bounds_map::test_ranges::ie;
use range_bounds_map::RangeBoundsMap;
let mut map = RangeBoundsMap::new();
map.insert_strict(ie(0, 5), true);
map.insert_strict(ie(5, 10), false);
assert_eq!(map.overlaps(ie(-2, 12)), true);
assert_eq!(map.contains_point(20), false);
assert_eq!(map.contains_point(5), true);
使用自定义RangeBounds
类型的示例
use std::ops::{Bound, RangeBounds};
use range_bounds_map::test_ranges::ie;
use range_bounds_map::RangeBoundsMap;
#[derive(Debug, Copy, Clone)]
enum Reservation {
// Start, End (Inclusive-Inclusive)
Finite(i8, i8),
// Start (Exclusive)
Infinite(i8),
}
// First, we need to implement RangeBounds
impl RangeBounds<i8> for Reservation {
fn start_bound(&self) -> Bound<&i8> {
match self {
Reservation::Finite(start, _) => {
Bound::Included(start)
}
Reservation::Infinite(start) => {
Bound::Excluded(start)
}
}
}
fn end_bound(&self) -> Bound<&i8> {
match self {
Reservation::Finite(_, end) => Bound::Included(end),
Reservation::Infinite(_) => Bound::Unbounded,
}
}
}
// Next we can create a custom typed RangeBoundsMap
let reservation_map = RangeBoundsMap::from_slice_strict([
(Reservation::Finite(10, 20), "Ferris".to_string()),
(Reservation::Infinite(20), "Corro".to_string()),
])
.unwrap();
for (reservation, name) in reservation_map.overlapping(ie(16, 17))
{
println!(
"{name} has reserved {reservation:?} inside the range 16..17"
);
}
for (reservation, name) in reservation_map.iter() {
println!("{name} has reserved {reservation:?}");
}
assert_eq!(
reservation_map.overlaps(Reservation::Infinite(0)),
true
);
键定义
无效区间
在此crate中,并非所有区间都被视为有效区间。在此crate中使用的区间有效性的定义是:一个区间仅在其包含至少一个基础域的值时才是有效的。
例如,4..6
被认为是有效的,因为它包含值4
和5
,然而,4..4
被认为是无效的,因为它不包含任何值。无效区间的另一个例子是起始值大于结束值的区间,例如5..2
或100..=40
。
以下是几个区间及其有效性的示例
区间 | 有效 |
---|---|
0..=0 | YES |
0..0 | NO |
0..1 | YES |
9..8 | NO |
(0.4)..=(-0.2) | NO |
..(-3) | YES |
0.0003.. | YES |
.. | YES |
400..=400 | YES |
重叠
两个范围“重叠”是指存在一个点同时包含在这两个范围之内。
接触
如果两个范围不重叠且它们之间没有其他值,则称它们“接触”。例如,2..4
和 4..6
是接触的,但 2..4
和 6..8
不是,同样 2..6
和 4..8
也不是。
合并
当一个范围“合并”其他范围时,它会吸收它们以变得更大。
进一步阅读
请参阅维基百科关于数学区间的文章:https://en.wikipedia.org/wiki/Interval_(mathematics)
改进/注意事项
- 我不得不创建一个新的特质:
TryFromBounds
,而不是使用TryFrom<(Bound, Bound)>
(依赖于上游实现,参见这个线程)
致谢
我最初想出了 StartBound
:Ord
的修补方案,但后来偶然发现 rangemap
也使用了 StartBound
:Ord
的修补方案。rangemap
因此成为了我的主要灵感来源。
后来我取消了 Ord
的修补方案,并切换到我自己完整的 BTreeMap
实现,该实现从 copse
启发,以提高其灵活性。
起源
这个库的目标是成为 rangemap
的更通用超集,这是根据 这个问题 和 这个拉取请求 进行的,我在其中将 rangemap
的 RangeMap
改为使用 RangeBounds
作为键之前,我意识到从头开始编写可能更容易、更简单。
类似的Crates
以下是一些我在研究相关主题时找到的相关Crates
- https://docs.rs/rangemap 与这个crate非常相似,但只能使用
Range
和RangeInclusive
作为其map
和set
结构体(分别)的键。 - https://docs.rs/btree-range-map
- https://docs.rs/ranges 这是一个通用的范围库(与std::ops ranges不同),还包括一个
Ranges
数据结构来存储它们(遗憾的是基于Vec) - https://docs.rs/intervaltree 允许重叠的区间,但遗憾的是不可变
- https://docs.rs/nonoverlapping_interval_tree 与rangemap非常相似,但没有
gaps()
函数,并且只针对Range
而不是RangeInclusive
。而且也没有复杂的合并函数。 - https://docs.rs/unbounded-interval-tree 基于一篇2007年发表的论文的数据结构!它还支持任何RangeBounds作为键,但是实现上使用了一个非平衡的
Box<Node>
树,然而它也支持重叠的RangeBounds,而我的库不支持。 - https://docs.rs/rangetree 我不确定这个库是做什么的,但看起来它是一个专门用于范围树的定制红黑树/BTree实现。有趣但也很旧(5年)且使用unsafe。
依赖项
~1–1.5MB
~33K SLoC