From 598ec70b5de1120a6a63c98a2559f387e64551e0 Mon Sep 17 00:00:00 2001 From: Aziz Kayumov Date: Tue, 17 Oct 2023 10:19:41 +0900 Subject: [PATCH 1/4] improve readability --- src/lctree.rs | 7 ++----- src/splay.rs | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/lctree.rs b/src/lctree.rs index dffa6c9..ae51369 100644 --- a/src/lctree.rs +++ b/src/lctree.rs @@ -1,7 +1,7 @@ use crate::{ node::{Node, Parent}, path::{FindMax, FindMin, FindSum, Path}, - splay::{splay, unflip, update}, + splay::{splay, unflip}, }; pub struct LinkCutTree { @@ -23,7 +23,6 @@ impl LinkCutTree { /// Constructs a path from a node to the root of the tree. fn access(&mut self, v: usize) { splay(&mut self.forest, v); - if let Some(right_idx) = self.forest[v].right { self.forest[v].right = None; self.forest[right_idx].parent = Parent::Path(v); @@ -43,9 +42,7 @@ impl LinkCutTree { splay(&mut self.forest, v); } - - // update aggregate information - update(&mut self.forest, v); + splay(&mut self.forest, v); } /// Makes v the root of its represented tree by flipping the path from v to the root. diff --git a/src/splay.rs b/src/splay.rs index 6a72720..a06b20f 100644 --- a/src/splay.rs +++ b/src/splay.rs @@ -121,18 +121,18 @@ pub fn splay(forest: &mut [Node], node_idx: usize) { { // zig-zig (same direction): rotate(forest, parent_idx); - rotate(forest, node_idx); } else { // zig-zag: rotate(forest, node_idx); - rotate(forest, node_idx); } + rotate(forest, node_idx); } else { // zig rotate(forest, node_idx); } } unflip(forest, node_idx); + update(forest, node_idx); } // Unflips the subtree rooted at `node_idx`, swapping the left and right children. From 9bf98b60bb990f553d7a7ae3bc5515c62f1ec53f Mon Sep 17 00:00:00 2001 From: Aziz Kayumov Date: Wed, 18 Oct 2023 09:43:14 +0900 Subject: [PATCH 2/4] clean up splay --- src/splay.rs | 16 ++++------------ tests/test_random.rs | 6 +++--- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/splay.rs b/src/splay.rs index a06b20f..13c6f62 100644 --- a/src/splay.rs +++ b/src/splay.rs @@ -37,10 +37,6 @@ fn rotate_left(forest: &mut [Node], node_idx: usize) { if let Some(new_right_child) = forest[node_idx].right { forest[new_right_child].parent = Parent::Node(node_idx); } - - // update aggregate information - update(forest, node_idx); - update(forest, right_child); } // Rotates the subtree rooted at `node_idx` to the right: @@ -77,10 +73,6 @@ fn rotate_right(forest: &mut [Node], node_idx: usize) { if let Some(new_left_child) = forest[node_idx].left { forest[new_left_child].parent = Parent::Node(node_idx); } - - // update aggregate information - update(forest, node_idx); - update(forest, left_child); } // Rotates the parent of `node_idx` to the right or left, depending on the relationship between. @@ -97,6 +89,8 @@ fn rotate(forest: &mut [Node], node_idx: usize) { } else { rotate_left(forest, parent_idx); } + update(forest, parent_idx); + update(forest, node_idx); } } @@ -125,11 +119,9 @@ pub fn splay(forest: &mut [Node], node_idx: usize) { // zig-zag: rotate(forest, node_idx); } - rotate(forest, node_idx); - } else { - // zig - rotate(forest, node_idx); } + // zig + rotate(forest, node_idx); } unflip(forest, node_idx); update(forest, node_idx); diff --git a/tests/test_random.rs b/tests/test_random.rs index b02b568..3354719 100644 --- a/tests/test_random.rs +++ b/tests/test_random.rs @@ -11,8 +11,7 @@ use std::{ }; fn create_random_generator() -> StdRng { - //let seed = rand::thread_rng().gen(); - let seed = 3900765363016383448; + let seed = rand::thread_rng().gen(); println!("Seed: {}", seed); // print seed so we can reproduce the test (if it fails). StdRng::seed_from_u64(seed) } @@ -199,8 +198,9 @@ impl BruteForce { } } +// These can be larger if you have time to spare (see tests/README.md) const NUMBER_OF_NODES: usize = 100; -const NUMBER_OF_OPERATIONS: usize = 2000; // can be larger if you have time to spare (see tests/README.md) +const NUMBER_OF_OPERATIONS: usize = 2000; #[derive(RandGen)] enum Operation { From fd532783b68143392d47b87a022934779e6ed748 Mon Sep 17 00:00:00 2001 From: Aziz Kayumov Date: Wed, 18 Oct 2023 17:29:13 +0900 Subject: [PATCH 3/4] use consistent terminology --- src/lctree.rs | 66 ++++++++++++++++----------------------------------- src/splay.rs | 17 +++++-------- 2 files changed, 27 insertions(+), 56 deletions(-) diff --git a/src/lctree.rs b/src/lctree.rs index ae51369..88a8f01 100644 --- a/src/lctree.rs +++ b/src/lctree.rs @@ -1,7 +1,7 @@ use crate::{ node::{Node, Parent}, - path::{FindMax, FindMin, FindSum, Path}, - splay::{splay, unflip}, + path::{FindMax, Path}, + splay::{normalize, splay}, }; pub struct LinkCutTree { @@ -40,7 +40,7 @@ impl LinkCutTree { self.forest[path_idx].right = Some(v); self.forest[v].parent = Parent::Node(path_idx); - splay(&mut self.forest, v); + splay(&mut self.forest, v); // just a rotation } splay(&mut self.forest, v); } @@ -49,7 +49,7 @@ impl LinkCutTree { fn reroot(&mut self, v: usize) { self.access(v); self.forest[v].flipped ^= true; - unflip(&mut self.forest, v); + normalize(&mut self.forest, v); } /// Checks if v and w are connected in the forest. @@ -112,34 +112,13 @@ impl Default for LinkCutTree { } } -impl LinkCutTree { - #[must_use] - pub fn findmax() -> Self { - Self::new() - } -} - -impl LinkCutTree { - #[must_use] - pub fn findmin() -> Self { - Self::new() - } -} - -impl LinkCutTree { - #[must_use] - pub fn findsum() -> Self { - Self::new() - } -} - #[cfg(test)] mod tests { - use crate::node::Parent; + use crate::{node::Parent, FindMin, FindSum, LinkCutTree}; #[test] pub fn access() { - let mut tree = super::LinkCutTree::findmax(); + let mut tree = super::LinkCutTree::default(); for i in 0..4 { tree.make_tree(i as f64); } @@ -425,12 +404,6 @@ mod tests { #[test] pub fn findmax() { - let mut lctree = super::LinkCutTree::default(); - let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; - for i in 0..weights.len() { - lctree.make_tree(weights[i]); - } - // We form a link-cut tree from the following rooted tree // (the numbers in parentheses are the weights of the nodes): // 0(9) @@ -442,6 +415,11 @@ mod tests { // 4(6) 7(3) // / \ // 8(7) 9(5) + let mut lctree = super::LinkCutTree::default(); + let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; + for i in 0..weights.len() { + lctree.make_tree(weights[i]); + } lctree.link(1, 0); lctree.link(2, 1); lctree.link(3, 1); @@ -464,12 +442,6 @@ mod tests { #[test] pub fn findmin() { - let mut lctree = super::LinkCutTree::findmin(); - let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; - for i in 0..weights.len() { - lctree.make_tree(weights[i]); - } - // We form a link-cut tree from the following rooted tree // (the numbers in parentheses are the weights of the nodes): // 0(9) @@ -481,6 +453,11 @@ mod tests { // 4(6) 7(3) // / \ // 8(7) 9(5) + let mut lctree: LinkCutTree = super::LinkCutTree::new(); + let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; + for i in 0..weights.len() { + lctree.make_tree(weights[i]); + } lctree.link(1, 0); lctree.link(2, 1); lctree.link(3, 1); @@ -503,12 +480,6 @@ mod tests { #[test] pub fn findsum() { - let mut lctree = super::LinkCutTree::findsum(); - let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; - for i in 0..weights.len() { - lctree.make_tree(weights[i]); - } - // We form a link-cut tree from the following rooted tree // (the numbers in parentheses are the weights of the nodes): // 0(9) @@ -520,6 +491,11 @@ mod tests { // 4(6) 7(3) // / \ // 8(7) 9(5) + let mut lctree: LinkCutTree = super::LinkCutTree::new(); + let weights = [9.0, 1.0, 8.0, 0.0, 6.0, 2.0, 4.0, 3.0, 7.0, 5.0]; + for i in 0..weights.len() { + lctree.make_tree(weights[i]); + } lctree.link(1, 0); lctree.link(2, 1); lctree.link(3, 1); diff --git a/src/splay.rs b/src/splay.rs index 13c6f62..eda1b6a 100644 --- a/src/splay.rs +++ b/src/splay.rs @@ -84,13 +84,14 @@ fn rotate(forest: &mut [Node], node_idx: usize) { ); if let Parent::Node(parent_idx) = forest[node_idx].parent { + normalize(forest, parent_idx); + normalize(forest, node_idx); if forest[parent_idx].left == Some(node_idx) { rotate_right(forest, parent_idx); } else { rotate_left(forest, parent_idx); } update(forest, parent_idx); - update(forest, node_idx); } } @@ -103,12 +104,6 @@ fn rotate(forest: &mut [Node], node_idx: usize) { // 2 pub fn splay(forest: &mut [Node], node_idx: usize) { while let Parent::Node(parent_idx) = forest[node_idx].parent { - if let Parent::Node(grandparent_idx) = forest[parent_idx].parent { - unflip(forest, grandparent_idx); - } - unflip(forest, parent_idx); - unflip(forest, node_idx); - if let Parent::Node(grandparent_idx) = forest[parent_idx].parent { if (forest[grandparent_idx].left == Some(parent_idx)) == (forest[parent_idx].left == Some(node_idx)) @@ -123,13 +118,13 @@ pub fn splay(forest: &mut [Node], node_idx: usize) { // zig rotate(forest, node_idx); } - unflip(forest, node_idx); + normalize(forest, node_idx); update(forest, node_idx); } // Unflips the subtree rooted at `node_idx`, swapping the left and right children. // The children's `flipped` flag is also toggled to propogate the change down the tree. -pub fn unflip(forest: &mut [Node], node_idx: usize) { +pub fn normalize(forest: &mut [Node], node_idx: usize) { if forest[node_idx].flipped { forest[node_idx].flipped = false; std::mem::swap(&mut forest[node_idx].left, &mut forest[node_idx].right); @@ -155,7 +150,7 @@ pub fn update(forest: &mut [Node], node_idx: usize) { #[cfg(test)] mod tests { - use super::{rotate, rotate_left, rotate_right, unflip}; + use super::{normalize, rotate, rotate_left, rotate_right}; use crate::{ node::{self, Node}, path::FindMax, @@ -360,7 +355,7 @@ mod tests { forest[1].parent = node::Parent::Node(0); forest[2].parent = node::Parent::Node(0); forest[0].flipped = true; - unflip(&mut forest, 0); + normalize(&mut forest, 0); assert!(!forest[0].flipped); assert!(forest[1].flipped); assert!(forest[2].flipped); From a8d230b21f31e6381b4fa4fc05b17ee1705b9f18 Mon Sep 17 00:00:00 2001 From: Aziz Kayumov Date: Wed, 18 Oct 2023 17:58:15 +0900 Subject: [PATCH 4/4] improve readability --- src/lctree.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lctree.rs b/src/lctree.rs index 88a8f01..d5b2e4c 100644 --- a/src/lctree.rs +++ b/src/lctree.rs @@ -1,7 +1,7 @@ use crate::{ node::{Node, Parent}, path::{FindMax, Path}, - splay::{normalize, splay}, + splay::{normalize, splay, update}, }; pub struct LinkCutTree { @@ -26,6 +26,7 @@ impl LinkCutTree { if let Some(right_idx) = self.forest[v].right { self.forest[v].right = None; self.forest[right_idx].parent = Parent::Path(v); + update(&mut self.forest, v); } while let Parent::Path(path_idx) = self.forest[v].parent { @@ -42,7 +43,6 @@ impl LinkCutTree { splay(&mut self.forest, v); // just a rotation } - splay(&mut self.forest, v); } /// Makes v the root of its represented tree by flipping the path from v to the root.