gpt4 book ai didi

rust - 从 HashSet 中获取具有最低值的元素?

转载 作者:行者123 更新时间:2023-11-29 08:25:03 24 4
gpt4 key购买 nike

我正在尝试使用一种方法创建堆,该方法返回具有最小 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)
}
}

结构:

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.pooliter() 方法不可变地借用了,因此 self.pool.take() 不能在同一时刻可变地借用它。

使此consume 方法获取并返回pool 中具有最小f 值的节点的最佳方法是什么?

注意事项:

  • 需要一个 Set(或 Map),因为其他方法需要在 O(1) 中检索任何节点
  • 我不使用有序集(这很容易解决上述问题),因为添加/更新操作必须保持 O(1)
  • heap 需要在删除 minimum-f 节点后访问,如示例所示

最佳答案

幸运的是,因为您正在按值获取 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
}

这确实需要您执行“额外的”散列查找。由于您要遍历整个 HashSet,因此这似乎是一个相对较小的成本。


如果您无法轻松克隆该元素,请系好安全带。使用来自 How to implement HashMap with two keys? 的想法,我们可以构建一个trait 对象,它可用于基于并行但等效的散列/相等实现来查找键:

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()
}

关于rust - 从 HashSet 中获取具有最低值的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50472697/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com