如何从BTreeMap修改/部分删除范围?

时间:2016-02-26 23:04:59

标签: rust

我正在尝试从RangeSet构建BTreeMap(其中键是下界,值是上限)。只要我只查找内容,这种方法就可以正常工作。然而,第一个改变方法让我难过:

如果我想插入范围到我的集合,我需要从尾部到头部的范围上限检查Range BTreeMap有问题的值低于插入范围的下限,所有包含的范围应删除且重叠范围合并。但是,即使使用当前不稳定的.range_mut(..),我也找不到删除条目的方法(因为地图仍然是从范围借来的)。

我是否使用了错误的工具?我能不能让它发挥作用 - 如果是这样,怎么样?我当前的伪代码解决方案(我也使用自己的Cut类型,因为Bound不是Ord):

fn insert(&mut self, range: &Range) {
    for entry in self.map.range_mut(Cut::Unbounded, range.upper).rev() {
         if entry.1 < range.lower {
             break;
         } else if entry.0 > range.lower {
             delete entry
         } else {
             merge entry with range
         }
     }
}

1 个答案:

答案 0 :(得分:2)

您需要在两次传递中执行此操作,收集要删除的键,然后迭代 列表并调用remove。

请注意,由于在树上迭代时会获得引用,因此您必须克隆/复制密钥,因为您将在地图内部引用某个键,这意味着您无法借用地图可变。

之所以这样,很大程度上是因为在迭代过程中删除条目时,内存和排序语义会有点不稳定。在迭代它时,删除树中的条目非常困难。这是一个地图,这意味着键在树中以某种方式排序,这意味着节点可能最终旋转他们的孩子,所以你可能以前访问过你的左孩子,现在突然之间就是你的当前节点或右子节点。很难跟踪你的位置。

此外,B-Tree节点是子节点列表,这些子节点具有动态,用于何时需要合并和拆分节点。在迭代过程中,这样做更令人头疼。

其中一些原因是手动记忆效应。密钥和值存储在节点内,而不是存储在堆上,因此内存将在整个地方反弹,并确保它不会失效是非常重要的。特别是如果用户正在收集循环中其他位置的树中条目的引用。

编辑:并且,无论可能性如何,问题的事实是迭代器借用了Map,这意味着你不能再次借用它来删除东西。如果迭代器返回类似Entry之类的东西,这可能会有所不同,但据我所知,没有迭代器可以存在。