我正在尝试使用一个方法创建一个堆,该方法返回具有最小f
- 值的节点,同时将其从堆本身中删除。
之后堆仍然可以使用,只有没有删除的值:
Node
结构及其实现:
use std::hash::{Hash, Hasher};
#[derive(Debug)]
struct Node {
x: f64,
y: f64,
f: f64,
}
impl Node {
fn to_bits(&self) -> u128 {
let xb = self.x.to_bits() as u128;
let yb = self.y.to_bits() as u128;
(xb << 64) + yb
}
}
impl PartialEq for Node {
fn eq(&self, other: &Node) -> bool {
self.x == other.x && self.y == other.y
}
}
impl Eq for Node {}
impl Hash for Node {
fn hash<H>(&self, state: &mut H) where H: Hasher {
self.to_bits().hash(state)
}
}
Heap
结构:
use std::f64;
use std::collections::HashSet;
#[derive(Debug)]
struct Heap {
pool: HashSet<Node>,
}
impl Heap {
fn add(mut self, node: Node) -> Heap {
self.pool.insert(node);
self
}
fn consume(mut self) -> Node {
// find the node with minimum f-value in self.pool
// and "take" it, aka remove it from the pool
// and then return it
Node { x: 0.0, y: 0.0, f: 0.0 } // dummy node so that the code compiles
}
}
main
函数:
fn main() {
let n1 = Node { x: 10.0, y: 11.0, f: 5.0 };
let n2 = Node { x: 11.0, y: 12.0, f: 7.0 };
let n3 = Node { x: 12.0, y: 13.0, f: 3.0 };
let n4 = Node { x: 14.0, y: 14.0, f: 4.0 };
let mut heap = Heap { pool: HashSet::new() };
heap = heap.add(n1);
heap = heap.add(n2);
heap = heap.add(n3);
heap = heap.add(n4);
let minimal_n1 = heap.consume();
println!("{:?}", minimal_n1);
// should print
// Node { x: 12.0, y: 13.0, f: 3.0 }
let minimal_n2 = heap.consume();
println!("{:?}", minimal_n2);
// should print
// Node { x: 14.0, y: 14.0, f: 4.0 }
println!("Heap has {} nodes", heap.pool.len());
// should print
// Heap has 2 nodes
}
以下是我迄今为止就consume
:
fn consume(mut self) -> Node {
let mut min_f = f64::MAX;
let mut min_node: Option<&Node> = None;
for n in self.pool.iter() {
if n.f < min_f {
min_f = n.f;
min_node = Some(n);
}
}
self.pool.take(&min_node.unwrap()).unwrap()
}
问题在于self.pool
是iter()
方法无法借用self.pool.take()
,因此consume
无法在同一时间可信地借用它。
使f
方法获取并返回pool
中具有最小heap
- 值的节点的最佳方法是什么?
注意:
A
,如示例所示答案 0 :(得分:3)
幸运的是,由于你按价值计算self
,这是一个很容易解决的问题。扔掉不是最小Node
的所有内容:
fn consume(self) -> Node {
self.pool
.into_iter()
.min_by(|a, b| a.f.partial_cmp(&b.f).expect("Found a NaN"))
.expect("There was no minimum")
}
如果之后需要保留Heap
,则需要在删除之前将找到的值与堆取消关联。克隆是最简单的解决方案:
fn consume(&mut self) -> Node {
let min = self.pool
.iter()
.min_by(|a, b| a.f.partial_cmp(&b.f).expect("Found a NaN"))
.cloned()
.expect("There was no minimum");
self.pool.remove(&min);
min
}
这确实要求您执行&#34;额外&#34;哈希查找。由于您正在遍历整个HashSet
,这似乎是一个相对较小的成本。
如果你不能轻易克隆元素,请扣紧。使用How to implement HashMap with two keys?中的想法,我们可以构建一个特征对象,可以用来根据并行但等效的哈希/等式实现来查找密钥:
use std::borrow::Borrow;
trait Key {
fn as_bits(&self) -> u128;
}
impl Key for Node {
fn as_bits(&self) -> u128 {
let xb = self.x.to_bits() as u128;
let yb = self.y.to_bits() as u128;
(xb << 64) + yb
}
}
impl Key for u128 {
fn as_bits(&self) -> u128 { *self }
}
impl<'a> Hash for Key + 'a {
fn hash<H: Hasher>(&self, h: &mut H) {
self.as_bits().hash(h)
}
}
impl<'a> PartialEq for Key + 'a {
fn eq(&self, other: &Self) -> bool {
self.as_bits() == other.as_bits()
}
}
impl<'a> Eq for Key + 'a {}
impl<'a> Borrow<Key + 'a> for Node {
fn borrow(&self) -> &(Key + 'a) {
self
}
}
impl<'a> Borrow<Key + 'a> for u128 {
fn borrow(&self) -> &(Key + 'a) {
self
}
}
有了这个支持,我们就可以将找到的元素转换为轻量级拥有的密钥,然后再使用它查找:
fn consume(&mut self) -> Node {
let min_key = self.pool
.iter()
.min_by(|a, b| a.f.partial_cmp(&b.f).expect("Found a NaN"))
.map(Node::as_bits)
.expect("There was no minimum");
let min_key: &Key = min_key.borrow();
self.pool.take(min_key).unwrap()
}