Add fibonacci_heap implementation
This commit is contained in:
parent
6cbb389ee7
commit
d2c1e6d422
6 changed files with 303 additions and 187 deletions
40
examples/priority_queue_test.rs
Normal file
40
examples/priority_queue_test.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use factorio_blueprint::priority_queue::{fibonacci_heap::FibonacciHeap, PriorityQueue};
|
||||
use std::fmt::Debug;
|
||||
|
||||
fn test_loop<P>()
|
||||
where
|
||||
P: PriorityQueue<u16> + Debug,
|
||||
{
|
||||
let mut input = String::new();
|
||||
|
||||
let mut p = P::new();
|
||||
|
||||
let mut handles = Vec::new();
|
||||
|
||||
loop {
|
||||
input.clear();
|
||||
std::io::stdin().read_line(&mut input);
|
||||
|
||||
let (cmd, arg) = input.trim().split_once(' ').unwrap_or((input.trim(), ""));
|
||||
// dbg!(cmd, arg);
|
||||
|
||||
match cmd {
|
||||
"i" => handles.push(p.insert(arg.parse::<u16>().unwrap())),
|
||||
"m" => println!("{:?}", p.pop_min()),
|
||||
"d" => {
|
||||
let (a, b) = arg.split_once(' ').unwrap();
|
||||
let h = &handles[a.parse::<usize>().unwrap()];
|
||||
let n = b.parse::<u16>().unwrap();
|
||||
p.decrease_key(h, |f| *f = n);
|
||||
}
|
||||
"p" => {
|
||||
dbg!(&p);
|
||||
}
|
||||
_ => println!("Unknown command."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_loop::<FibonacciHeap<u16>>()
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
use factorio_blueprint::belt_finding::{common::Position, Problem};
|
||||
|
||||
fn main() {
|
||||
let mut p = Problem::new(33, 13);
|
||||
|
||||
p.set_blocked_range(1, 3, 2, 5, true);
|
||||
p.set_blocked_range(1, 7, 2, 9, true);
|
||||
|
||||
p.set_blocked(0, 3, true);
|
||||
p.set_blocked(0, 8, true);
|
||||
|
||||
p.set_blocked_range(10, 0, 21, 2, true);
|
||||
p.set_blocked_range(10, 5, 21, 7, true);
|
||||
p.set_blocked_range(10, 10, 21, 12, true);
|
||||
|
||||
p.set_blocked_range(30, 3, 31, 5, true);
|
||||
p.set_blocked_range(30, 7, 31, 9, true);
|
||||
p.set_blocked(32, 3, true);
|
||||
p.set_blocked(32, 9, true);
|
||||
|
||||
p.add_connection(Position::new(3, 3), Position::new(29, 7));
|
||||
p.add_connection(Position::new(3, 4), Position::new(29, 9));
|
||||
p.add_connection(Position::new(3, 5), Position::new(29, 8));
|
||||
|
||||
p.add_connection(Position::new(3, 7), Position::new(29, 3));
|
||||
p.add_connection(Position::new(3, 8), Position::new(29, 5));
|
||||
p.add_connection(Position::new(3, 9), Position::new(29, 4));
|
||||
|
||||
println!("{p}");
|
||||
p.find_path();
|
||||
println!("{p}");
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
||||
use crate::graph::wheighted_graph::WheightedGraph;
|
||||
use crate::misc::Map;
|
||||
use crate::priority_queue::BinaryHeap;
|
||||
use crate::{
|
||||
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
|
||||
};
|
||||
use std::ops::Index;
|
||||
use termcolor::{Color, ColorSpec};
|
||||
|
||||
|
|
@ -208,7 +210,7 @@ impl Problem {
|
|||
for i in 0..self.start.len() {
|
||||
self.calculate_wheights(i);
|
||||
let m = MapInternal { map: &self.map };
|
||||
let p = dijkstra::<MapInternal, BinaryHeap<_>>(&m, self.start[i], self.end[i]);
|
||||
let p = dijkstra::<MapInternal, FibonacciHeap<_>>(&m, self.start[i], self.end[i]);
|
||||
|
||||
if let Some(p) = p {
|
||||
self.path[i] = p;
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ mod test {
|
|||
graph::wheighted_graph::{
|
||||
adjacency_list::WheightedAdjacencyList, shortest_path::dijkstra, WheightedGraph,
|
||||
},
|
||||
priority_queue::BinaryHeap,
|
||||
priority_queue::{fibonacci_heap::FibonacciHeap, BinaryHeap},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -162,6 +162,14 @@ mod test {
|
|||
dijkstra::<WheightedAdjacencyList, BinaryHeap<_>>(&a, 0, 6),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 4),
|
||||
Some(vec![0, 1, 2, 5, 4])
|
||||
);
|
||||
assert_eq!(
|
||||
dijkstra::<WheightedAdjacencyList, FibonacciHeap<_>>(&a, 0, 6),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
struct Grid {
|
||||
|
|
|
|||
|
|
@ -1,186 +1,280 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use crate::misc::{Arena, ArenaKey};
|
||||
|
||||
use super::PriorityQueue;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FibonacciHeapObject<T> {
|
||||
left: ArenaKey,
|
||||
right: ArenaKey,
|
||||
parent: Option<ArenaKey>,
|
||||
child: Option<ArenaKey>,
|
||||
rank: usize,
|
||||
marked: bool,
|
||||
data: T,
|
||||
type Index = u32;
|
||||
|
||||
pub struct FibonacciHeap<I> {
|
||||
min: Option<Index>,
|
||||
data: Vec<Option<Node<I>>>,
|
||||
free: Vec<Index>,
|
||||
temp: [Option<Index>; 64],
|
||||
}
|
||||
|
||||
impl<I: std::fmt::Debug> std::fmt::Debug for FibonacciHeap<I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
struct PrintData<'a, I>(&'a Vec<Option<Node<I>>>);
|
||||
impl<'a, I: Debug> Debug for PrintData<'a, I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_map()
|
||||
.entries(self.0.iter().enumerate().filter_map(|d| {
|
||||
if let (i, Some(c)) = d {
|
||||
Some((i, c))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
f.debug_struct("FibonacciHeap")
|
||||
.field("min", &self.min)
|
||||
.field("data", &PrintData(&self.data))
|
||||
.field("free", &self.free)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FibonacciHeap<T> {
|
||||
arena: Arena<FibonacciHeapObject<T>>,
|
||||
min: Option<ArenaKey>,
|
||||
update_rank: Vec<Option<ArenaKey>>,
|
||||
pub struct FibonacciHeapHandle(Index);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node<I> {
|
||||
item: I,
|
||||
parent: Index,
|
||||
left: Index,
|
||||
right: Index,
|
||||
child: Index,
|
||||
mark: bool,
|
||||
rank: u16,
|
||||
}
|
||||
|
||||
pub struct FibonacciHeapHandle(ArenaKey);
|
||||
impl<I> Node<I> {
|
||||
fn new(item: I) -> Self {
|
||||
Self {
|
||||
item,
|
||||
parent: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: 0,
|
||||
mark: false,
|
||||
rank: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PriorityQueue<T> for FibonacciHeap<T>
|
||||
impl<I> FibonacciHeap<I>
|
||||
where
|
||||
T: std::cmp::Ord,
|
||||
I: PartialOrd,
|
||||
{
|
||||
fn add_to_list(&mut self, list: Index, i: Index) {
|
||||
let right = self.get(list).right;
|
||||
let n = self.get_mut(i);
|
||||
n.right = right;
|
||||
n.left = list;
|
||||
self.get_mut(right).left = i;
|
||||
self.get_mut(list).right = i;
|
||||
}
|
||||
|
||||
fn remove_from_list(&mut self, i: Index) -> Option<Index> {
|
||||
let left = self.get(i).left;
|
||||
if left == i {
|
||||
return None;
|
||||
}
|
||||
|
||||
let right = self.get(i).right;
|
||||
|
||||
self.get_mut(left).right = right;
|
||||
self.get_mut(right).left = left;
|
||||
|
||||
Some(right)
|
||||
}
|
||||
|
||||
fn insert_tree(&mut self, i: Index) {
|
||||
if let Some(min) = self.min {
|
||||
self.add_to_list(min, i);
|
||||
|
||||
self.get_mut(i).parent = i;
|
||||
|
||||
if self.get(i).item < self.get(min).item {
|
||||
self.min = Some(i);
|
||||
}
|
||||
} else {
|
||||
let m = self.get_mut(i);
|
||||
m.parent = i;
|
||||
m.left = i;
|
||||
m.right = i;
|
||||
self.min = Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
fn union(&mut self, a: Index, b: Index) -> Index {
|
||||
let min;
|
||||
let max;
|
||||
|
||||
if self.get(a).item < self.get(b).item {
|
||||
min = a;
|
||||
max = b;
|
||||
} else {
|
||||
min = b;
|
||||
max = a;
|
||||
}
|
||||
|
||||
if self.get(min).rank == 0 {
|
||||
self.get_mut(min).child = max;
|
||||
self.get_mut(min).rank = 1;
|
||||
let m = self.get_mut(max);
|
||||
m.parent = min;
|
||||
m.left = max;
|
||||
m.right = max;
|
||||
} else {
|
||||
self.get_mut(max).parent = min;
|
||||
self.add_to_list(self.get(min).child, max);
|
||||
self.get_mut(min).rank += 1;
|
||||
}
|
||||
|
||||
min
|
||||
}
|
||||
fn insert_temp(&mut self, i: Index) {
|
||||
let rank = self.get(i).rank;
|
||||
if let Some(t) = self.temp[rank as usize].take() {
|
||||
let m = self.union(t, i);
|
||||
|
||||
self.insert_temp(m);
|
||||
} else {
|
||||
self.temp[rank as usize] = Some(i);
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_data(&mut self, data: I) -> Index {
|
||||
if let Some(i) = self.free.pop() {
|
||||
self.data[i as usize] = Some(Node::new(data));
|
||||
i
|
||||
} else {
|
||||
let i = self.data.len() as Index;
|
||||
self.data.push(Some(Node::new(data)));
|
||||
i
|
||||
}
|
||||
}
|
||||
|
||||
fn get(&self, i: Index) -> &Node<I> {
|
||||
self.data.get(i as usize).unwrap().as_ref().unwrap()
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, i: Index) -> &mut Node<I> {
|
||||
self.data.get_mut(i as usize).unwrap().as_mut().unwrap()
|
||||
}
|
||||
|
||||
fn remove_data(&mut self, i: Index) -> I {
|
||||
let n = self.data[i as usize].take().unwrap();
|
||||
|
||||
self.free.push(i);
|
||||
|
||||
n.item
|
||||
}
|
||||
|
||||
fn cut(&mut self, i: Index) {
|
||||
if self.get(i).item < self.get(self.min.unwrap()).item {
|
||||
self.min = Some(i);
|
||||
}
|
||||
let parent = self.get(i).parent;
|
||||
if parent == i {
|
||||
return;
|
||||
}
|
||||
let c = self.remove_from_list(i);
|
||||
if self.get(parent).rank > 1 {
|
||||
self.get_mut(parent).child = c.unwrap();
|
||||
}
|
||||
self.get_mut(parent).rank -= 1;
|
||||
|
||||
self.add_to_list(self.min.unwrap(), i);
|
||||
self.get_mut(i).mark = false;
|
||||
self.get_mut(i).parent = i;
|
||||
|
||||
if self.get(parent).mark {
|
||||
self.cut(parent);
|
||||
} else {
|
||||
self.get_mut(parent).mark = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I> PriorityQueue<I> for FibonacciHeap<I>
|
||||
where
|
||||
I: PartialOrd,
|
||||
{
|
||||
type Handle = FibonacciHeapHandle;
|
||||
|
||||
fn new() -> Self {
|
||||
todo!()
|
||||
FibonacciHeap {
|
||||
min: None,
|
||||
data: Vec::new(),
|
||||
free: Vec::new(),
|
||||
temp: [None; 64],
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, item: T) -> Self::Handle {
|
||||
let h = self.arena.insert(FibonacciHeapObject {
|
||||
left: ArenaKey::default(),
|
||||
right: ArenaKey::default(),
|
||||
parent: None,
|
||||
child: None,
|
||||
rank: 0,
|
||||
marked: false,
|
||||
data: item,
|
||||
});
|
||||
fn insert(&mut self, item: I) -> Self::Handle {
|
||||
let i = self.insert_data(item);
|
||||
|
||||
self.insert_tree(h);
|
||||
self.insert_tree(i);
|
||||
|
||||
FibonacciHeapHandle(h)
|
||||
FibonacciHeapHandle(i)
|
||||
}
|
||||
|
||||
fn pop_min(&mut self) -> Option<T> {
|
||||
if let Some(k) = self.min.take() {
|
||||
let o = self.arena.remove(k);
|
||||
|
||||
if let Some(child) = o.child {
|
||||
let mut p = child;
|
||||
fn pop_min(&mut self) -> Option<I> {
|
||||
if let Some(min) = self.min.take() {
|
||||
if self.get(min).rank != 0 {
|
||||
let mut c = self.get(min).child;
|
||||
loop {
|
||||
self.arena.get_mut(&p).parent = None;
|
||||
self.arena.get_mut(&p).marked = false;
|
||||
let t = self.arena.get(&p).right;
|
||||
|
||||
self.insert_tree(p);
|
||||
|
||||
p = t;
|
||||
|
||||
if p == child {
|
||||
let t = c;
|
||||
c = self.get(c).right;
|
||||
self.add_to_list(min, t);
|
||||
self.get_mut(t).parent = t;
|
||||
self.get_mut(t).mark = false;
|
||||
if c == self.get(min).child {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(m) = self.remove_from_list(min) {
|
||||
let mut c = m;
|
||||
loop {
|
||||
let t = c;
|
||||
c = self.get(c).right;
|
||||
self.insert_temp(t);
|
||||
if c == m {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if o.left != o.right {
|
||||
self.arena.get_mut(&o.left).right = o.right;
|
||||
self.arena.get_mut(&o.right).left = o.left;
|
||||
self.update_min(o.left);
|
||||
for i in 0..self.temp.len() {
|
||||
if let Some(i) = self.temp[i].take() {
|
||||
if let Some(min) = self.min {
|
||||
self.add_to_list(min, i);
|
||||
if self.get(i).item < self.get(min).item {
|
||||
self.min = Some(i);
|
||||
}
|
||||
} else {
|
||||
self.get_mut(i).left = i;
|
||||
self.get_mut(i).right = i;
|
||||
self.min = Some(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(o.data)
|
||||
Some(self.remove_data(min))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn decrease_key(&mut self, _handle: &Self::Handle, _f: impl Fn(&mut T)) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FibonacciHeap<T>
|
||||
where
|
||||
T: std::cmp::Ord,
|
||||
{
|
||||
fn insert_tree(&mut self, h: ArenaKey) {
|
||||
if let Some(h_min) = self.min {
|
||||
let h_last = self.arena.get(&h_min).left;
|
||||
|
||||
self.arena.get_mut(&h_min).left = h;
|
||||
|
||||
self.arena.get_mut(&h).left = h_last;
|
||||
self.arena.get_mut(&h).right = h_min;
|
||||
|
||||
self.arena.get_mut(&h_last).right = h;
|
||||
|
||||
if self.arena.get(&h).data < self.arena.get(&h_min).data {
|
||||
self.min = Some(h)
|
||||
}
|
||||
} else {
|
||||
self.arena.get_mut(&h).left = h;
|
||||
self.arena.get_mut(&h).right = h;
|
||||
|
||||
self.min = Some(h);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_min(&mut self, mut h: ArenaKey) {
|
||||
let h_start = h;
|
||||
|
||||
loop {
|
||||
let next_h = self.arena.get(&h).right;
|
||||
|
||||
self.add_to_update_rank(h);
|
||||
|
||||
h = next_h;
|
||||
if h == h_start {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let mut prev = None;
|
||||
// let mut start = None;
|
||||
|
||||
for h in &mut self.update_rank {
|
||||
if let Some(h) = h.take() {
|
||||
if let Some(p) = prev {
|
||||
self.arena.get_mut(&h).left = p;
|
||||
self.arena.get_mut(&p).right = h;
|
||||
} else {
|
||||
prev = Some(h);
|
||||
// start = Some(h);
|
||||
}
|
||||
if let Some(m) = self.min {
|
||||
if self.arena.get(&h).data < self.arena.get(&m).data {
|
||||
self.min = Some(h);
|
||||
}
|
||||
} else {
|
||||
self.min = Some(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_to_update_rank(&mut self, h: ArenaKey) {
|
||||
let rank = self.arena.get(&h).rank;
|
||||
|
||||
while self.update_rank.len() + 1 < rank {
|
||||
self.update_rank.push(None)
|
||||
}
|
||||
|
||||
if let Some(o) = self.update_rank.get_mut(rank).unwrap().take() {
|
||||
if let Some(child) = self.arena.get(&h).child {
|
||||
let last = self.arena.get(&child).left;
|
||||
|
||||
self.arena.get_mut(&child).left = h;
|
||||
self.arena.get_mut(&last).right = h;
|
||||
|
||||
self.arena.get_mut(&o).parent = Some(h);
|
||||
self.arena.get_mut(&o).marked = false;
|
||||
self.arena.get_mut(&o).left = last;
|
||||
self.arena.get_mut(&o).right = child;
|
||||
} else {
|
||||
self.arena.get_mut(&h).child = Some(o);
|
||||
|
||||
self.arena.get_mut(&o).parent = Some(h);
|
||||
self.arena.get_mut(&o).marked = false;
|
||||
self.arena.get_mut(&o).left = o;
|
||||
self.arena.get_mut(&o).right = o;
|
||||
}
|
||||
|
||||
self.arena.get_mut(&h).rank += 1;
|
||||
|
||||
self.add_to_update_rank(h);
|
||||
} else {
|
||||
*self.update_rank.get_mut(rank).unwrap() = Some(h);
|
||||
}
|
||||
fn decrease_key(&mut self, handle: &Self::Handle, f: impl Fn(&mut I)) {
|
||||
let h = self.get_mut(handle.0);
|
||||
f(&mut h.item);
|
||||
self.cut(handle.0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ where
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::fibonacci_heap::FibonacciHeap;
|
||||
use super::BinaryHeap;
|
||||
use super::PriorityQueue;
|
||||
|
||||
macro_rules! test_generics {
|
||||
|
|
@ -124,12 +126,14 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn $fun() {
|
||||
super::$fun::<super::super::$gen<usize>>();
|
||||
super::super::$fun::<super::super::$gen<usize>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_generics!(basic_generic decrease_key_generic; BinaryHeap);
|
||||
mod test_macro {
|
||||
test_generics!(basic_generic decrease_key_generic; BinaryHeap FibonacciHeap);
|
||||
}
|
||||
|
||||
fn basic_generic<T: PriorityQueue<usize>>() {
|
||||
let mut q = T::new();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue