Skip to content

Commit

Permalink
Merge pull request #34 from azizkayumov/develop
Browse files Browse the repository at this point in the history
Improve code readability
  • Loading branch information
azizkayumov committed Oct 19, 2023
2 parents fcd34f8 + a8d230b commit ff0c149
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 75 deletions.
71 changes: 22 additions & 49 deletions src/lctree.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
node::{Node, Parent},
path::{FindMax, FindMin, FindSum, Path},
splay::{splay, unflip, update},
path::{FindMax, Path},
splay::{normalize, splay, update},
};

pub struct LinkCutTree<T: Path> {
Expand All @@ -23,10 +23,10 @@ impl<T: Path> LinkCutTree<T> {
/// 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);
update(&mut self.forest, v);
}

while let Parent::Path(path_idx) = self.forest[v].parent {
Expand All @@ -41,18 +41,15 @@ impl<T: Path> LinkCutTree<T> {
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
}

// update aggregate information
update(&mut self.forest, v);
}

/// Makes v the root of its represented tree by flipping the path from v to the root.
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.
Expand Down Expand Up @@ -115,34 +112,13 @@ impl Default for LinkCutTree<FindMax> {
}
}

impl LinkCutTree<FindMax> {
#[must_use]
pub fn findmax() -> Self {
Self::new()
}
}

impl LinkCutTree<FindMin> {
#[must_use]
pub fn findmin() -> Self {
Self::new()
}
}

impl LinkCutTree<FindSum> {
#[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);
}
Expand Down Expand Up @@ -428,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)
Expand All @@ -445,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);
Expand All @@ -467,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)
Expand All @@ -484,6 +453,11 @@ mod tests {
// 4(6) 7(3)
// / \
// 8(7) 9(5)
let mut lctree: LinkCutTree<FindMin> = 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);
Expand All @@ -506,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)
Expand All @@ -523,6 +491,11 @@ mod tests {
// 4(6) 7(3)
// / \
// 8(7) 9(5)
let mut lctree: LinkCutTree<FindSum> = 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);
Expand Down
33 changes: 10 additions & 23 deletions src/splay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ fn rotate_left<T: Path>(forest: &mut [Node<T>], 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:
Expand Down Expand Up @@ -77,10 +73,6 @@ fn rotate_right<T: Path>(forest: &mut [Node<T>], 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.
Expand All @@ -92,11 +84,14 @@ fn rotate<T: Path>(forest: &mut [Node<T>], 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);
}
}

Expand All @@ -109,35 +104,27 @@ fn rotate<T: Path>(forest: &mut [Node<T>], node_idx: usize) {
// 2
pub fn splay<T: Path>(forest: &mut [Node<T>], 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))
{
// zig-zig (same direction):
rotate(forest, parent_idx);
rotate(forest, node_idx);
} else {
// 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);
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<T: Path>(forest: &mut [Node<T>], node_idx: usize) {
pub fn normalize<T: Path>(forest: &mut [Node<T>], 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);
Expand All @@ -163,7 +150,7 @@ pub fn update<T: Path + Copy + Clone>(forest: &mut [Node<T>], 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,
Expand Down Expand Up @@ -368,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);
Expand Down
6 changes: 3 additions & 3 deletions tests/test_random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit ff0c149

Please sign in to comment.