Rust で SkewHeap を書いてみた
タイトルのまんま.
純粋関数型データ構造っぽさを意識して書いてみました.
use std::rc::Rc; enum SkewHeap<T: Ord + Clone> { Empty, Node(T, Rc<SkewHeap<T>>, Rc<SkewHeap<T>>) } impl<T: Ord + Clone> Clone for SkewHeap<T> { fn clone(&self) -> SkewHeap<T> { match *self { SkewHeap::Empty => SkewHeap::Empty, SkewHeap::Node(ref v, ref l, ref r) => SkewHeap::Node((*v).clone(), (*l).clone(), (*r).clone()), } } } impl<T: Ord + Clone> SkewHeap<T> { fn push(&self, val: T) -> SkewHeap<T> { self.meld(SkewHeap::Node(val, Rc::new(SkewHeap::Empty), Rc::new(SkewHeap::Empty))) } fn meld(&self, other: SkewHeap<T>) -> SkewHeap<T> { match *self { SkewHeap::Empty => other.clone(), SkewHeap::Node(ref v1, ref l1, ref r1) => { match other { SkewHeap::Empty => self.clone(), SkewHeap::Node(ref v2, ref l2, ref r2) => { if v1 < v2 { let r = r1.clone(); //SkewHeap::Node(v1.clone(), l1.clone(), Rc::new(r.meld(other.clone()))) SkewHeap::Node(v1.clone(), Rc::new(r.meld(other.clone())), l1.clone()) } else { let r = r2.clone(); //SkewHeap::Node(v2.clone(), l2.clone(), Rc::new(r.meld(self.clone()))) SkewHeap::Node(v2.clone(), Rc::new(r.meld(self.clone())), l2.clone()) } } } } } } fn pop(&self) -> (Option<T>, SkewHeap<T>) { match *self { SkewHeap::Empty => (None, SkewHeap::Empty), SkewHeap::Node(ref v, ref l, ref r) => { (Some(v.clone()), l.meld((**r).clone())) } } } }
使ってみた
試しに以下の問題を解いてみた.
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_9_C
結果は 3.99 sec で TLE.まあ clone しまくってるのでそれはそう.予想より早い(もっと遅いと思っていた)
追記
木の形偏ってるなあと思っていたら,meld するときに swap するの忘れてた.すると 3.99 sec から 3.07 sec に改善した.
感想
もし競プロならこのままだと使えない.純粋関数型っぽさを捨てれば早いのは書ける.Rust はライフタイムの制約が厳しすぎて,変更が加わらなかったノードは共有するみたいなコードを書くのが難しい.どうかけばいいかわからん.