From cf5c9372de29c7262a82d68f057aecb63f786cfe Mon Sep 17 00:00:00 2001 From: Abduaziz Kayumov Date: Wed, 27 Sep 2023 14:30:21 +0900 Subject: [PATCH 1/3] closes #2 --- src/access.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/splay.rs | 9 ++++--- 3 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/access.rs diff --git a/src/access.rs b/src/access.rs new file mode 100644 index 0000000..99b9ebd --- /dev/null +++ b/src/access.rs @@ -0,0 +1,67 @@ +use crate::{node::{Node, Parent}, splay::splay}; + +// constructs a path from the root to the node at idx +pub fn access(forest: &mut Vec, node_idx: usize) { + splay(forest, node_idx); + + if let Some(right_idx) = forest[node_idx].right { + forest[node_idx].right = None; + forest[right_idx].parent = Parent::Path(node_idx); + } + + while let Parent::Path(path_idx) = forest[node_idx].parent { + splay(forest, path_idx); + // detach the right child of the path parent + if let Some(right_idx) = forest[path_idx].right { + forest[right_idx].parent = Parent::Path(path_idx); + forest[path_idx].right = None; + } + + // attach the node as the path parent's right child + forest[path_idx].right = Some(node_idx); + forest[node_idx].parent = Parent::Node(path_idx); + splay(forest, node_idx); + } +} + +#[cfg(test)] +mod tests { + use crate::node::{Node, Parent}; + + fn create_nodes(n: usize) -> Vec { + (0..n).map(|i| Node::new(i, 0.0)).collect() + } + + #[test] + pub fn access_base_case() { + // access a single node, should do nothing + let mut forest = create_nodes(1); + super::access(&mut forest, 0); + assert!(matches!(forest[0].parent, Parent::Root)); + } + + #[test] + pub fn access_splay_leaf() { + let mut forest = create_nodes(3); + // '1' has a path pointer to '0', '1' has a right child '2'. + // after access(2), '2' should be the root of the tree: + // 0 0 0 2 + // | | \ / + // 1 => 2 => 2 => 0 + // \ / / \ + // 2 1 1 1 + forest[1].parent = Parent::Path(0); + forest[1].right = Some(2); + forest[2].parent = Parent::Path(1); + super::access(&mut forest, 2); + assert!(matches!(forest[2].parent, Parent::Root)); + assert_eq!(forest[2].right, None); + assert_eq!(forest[2].left, Some(0)); + assert!(matches!(forest[0].parent, Parent::Node(2))); + assert_eq!(forest[0].left, None); + assert_eq!(forest[0].right, Some(1)); + assert!(matches!(forest[1].parent, Parent::Node(0))); + assert_eq!(forest[1].left, None); + assert_eq!(forest[1].right, None); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 14f9b4f..694f6c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ #![allow(dead_code, clippy::module_name_repetitions)] // yes, I want to name my structs with the same name as the file mod node; mod splay; +mod access; diff --git a/src/splay.rs b/src/splay.rs index acee868..864a262 100644 --- a/src/splay.rs +++ b/src/splay.rs @@ -1,6 +1,6 @@ use crate::node::{Node, Parent}; -pub fn rotate_left(forest: &mut Vec, node_idx: usize) { +fn rotate_left(forest: &mut Vec, node_idx: usize) { // base cases: // - node_idx is out of bounds // - node_idx should have a right child @@ -27,7 +27,7 @@ pub fn rotate_left(forest: &mut Vec, node_idx: usize) { } } -pub fn rotate_right(forest: &mut Vec, node_idx: usize) { +fn rotate_right(forest: &mut Vec, node_idx: usize) { // base cases: // - node_idx is out of bounds // - node_idx should have a left child @@ -118,8 +118,9 @@ mod tests { forest[0].right = Some(1); forest[1].parent = node::Parent::Node(0); rotate_left(&mut forest, 0); - assert_eq!(forest[0].right, None); assert_eq!(forest[1].left, Some(0)); + assert_eq!(forest[0].right, None); + assert_eq!(forest[0].left, None); assert!(matches!(forest[0].parent, node::Parent::Node(1))); assert!(matches!(forest[1].parent, node::Parent::Root)); } @@ -233,7 +234,9 @@ mod tests { forest[1].parent = node::Parent::Node(0); super::splay(&mut forest, 1); assert_eq!(forest[0].right, None); + assert_eq!(forest[0].left, None); assert_eq!(forest[1].left, Some(0)); + assert_eq!(forest[1].right, None); assert!(matches!(forest[0].parent, node::Parent::Node(1))); assert!(matches!(forest[1].parent, node::Parent::Root)); } From fcb7171fbe95423966ac6bd38971a1f6215b73f7 Mon Sep 17 00:00:00 2001 From: Abduaziz Kayumov Date: Wed, 27 Sep 2023 14:51:22 +0900 Subject: [PATCH 2/3] fix test --- src/access.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/access.rs b/src/access.rs index 99b9ebd..02583de 100644 --- a/src/access.rs +++ b/src/access.rs @@ -16,7 +16,7 @@ pub fn access(forest: &mut Vec, node_idx: usize) { forest[right_idx].parent = Parent::Path(path_idx); forest[path_idx].right = None; } - + // attach the node as the path parent's right child forest[path_idx].right = Some(node_idx); forest[node_idx].parent = Parent::Node(path_idx); @@ -52,7 +52,7 @@ mod tests { // 2 1 1 1 forest[1].parent = Parent::Path(0); forest[1].right = Some(2); - forest[2].parent = Parent::Path(1); + forest[2].parent = Parent::Node(1); super::access(&mut forest, 2); assert!(matches!(forest[2].parent, Parent::Root)); assert_eq!(forest[2].right, None); From 820813127954b4cba153f311bbe20e847ffaa1bc Mon Sep 17 00:00:00 2001 From: Abduaziz Kayumov Date: Wed, 27 Sep 2023 14:54:30 +0900 Subject: [PATCH 3/3] make clippy happy --- src/access.rs | 7 +++++-- src/lib.rs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/access.rs b/src/access.rs index 02583de..1bc98e3 100644 --- a/src/access.rs +++ b/src/access.rs @@ -1,4 +1,7 @@ -use crate::{node::{Node, Parent}, splay::splay}; +use crate::{ + node::{Node, Parent}, + splay::splay, +}; // constructs a path from the root to the node at idx pub fn access(forest: &mut Vec, node_idx: usize) { @@ -64,4 +67,4 @@ mod tests { assert_eq!(forest[1].left, None); assert_eq!(forest[1].right, None); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 694f6c3..d7175c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ #![allow(dead_code, clippy::module_name_repetitions)] // yes, I want to name my structs with the same name as the file +mod access; mod node; mod splay; -mod access;