#map #interval-tree #library #data

nightly range_bounds_map

这个crate提供了[RangeBoundsMap]和[RangeBoundsSet],基于[BTreeMap]存储非重叠区间的数据结构

15个不稳定版本 (3个破坏性更新)

0.4.0 2023年4月24日
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

AGPL-3.0-or-later

120KB
2.5K SLoC

range_bounds_map

License Docs Maintained Crates.io

range_bounds_map_logo

这个crate已被重命名为nodit

这个crate从range_bounds_map重命名为discrete_range_map,现在名为nodit,因为旧名称已不准确。请切换到nodit crate,因为这个crate将不再接收更新。

旧版自述文件

这个crate提供了RangeBoundsMapRangeBoundsSet,基于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被认为是有效的,因为它包含值45,然而,4..4被认为是无效的,因为它不包含任何值。无效区间的另一个例子是起始值大于结束值的区间,例如5..2100..=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..44..6 是接触的,但 2..46..8 不是,同样 2..64..8 也不是。

合并

当一个范围“合并”其他范围时,它会吸收它们以变得更大。

进一步阅读

请参阅维基百科关于数学区间的文章:https://en.wikipedia.org/wiki/Interval_(mathematics)

改进/注意事项

  • 我不得不创建一个新的特质:TryFromBounds,而不是使用 TryFrom<(Bound, Bound)>(依赖于上游实现,参见这个线程

致谢

我最初想出了 StartBoundOrd 的修补方案,但后来偶然发现 rangemap 也使用了 StartBoundOrd 的修补方案。rangemap 因此成为了我的主要灵感来源。

后来我取消了 Ord 的修补方案,并切换到我自己完整的 BTreeMap 实现,该实现从 copse 启发,以提高其灵活性。

起源

这个库的目标是成为 rangemap 的更通用超集,这是根据 这个问题这个拉取请求 进行的,我在其中将 rangemapRangeMap 改为使用 RangeBounds 作为键之前,我意识到从头开始编写可能更容易、更简单。

类似的Crates

以下是一些我在研究相关主题时找到的相关Crates

nodit https://docs.rs/nodit

依赖项

~1–1.5MB
~33K SLoC