diff --git a/src/binary_tree.rs b/src/binary_tree.rs new file mode 100644 index 0000000..d6e985c --- /dev/null +++ b/src/binary_tree.rs @@ -0,0 +1,194 @@ +use std::collections::VecDeque; +#[cfg(test)] +mod tests { + use super::BinaryTree; + + #[test] + fn create_new_tree() { + let tree = BinaryTree::new(1); + + assert_eq!(tree.value, 1); + } + + #[test] + fn insert_left() { + let tree = BinaryTree::new(1).left(BinaryTree::new(2)); + + if let Some(node) = tree.left { + assert_eq!(node.value, 2); + } + + assert_eq!(tree.right, None); + } + + #[test] + fn insert_right() { + let tree = BinaryTree::new(1).right(BinaryTree::new(2)); + + if let Some(node) = tree.right { + assert_eq!(node.value, 2); + } + + assert_eq!(tree.left, None); + } + #[test] + fn insert() { + let mut tree = BinaryTree::new(1); + tree.insert(2); + tree.insert(3); + tree.insert(4); + tree.insert(5); + + assert_eq!( + tree, + BinaryTree::new(1) + .left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5))) + .right(BinaryTree::new(3)) + ); + + tree.insert(6); + + assert_eq!( + tree, + BinaryTree::new(1) + .left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5))) + .right(BinaryTree::new(3).left(BinaryTree::new(6))) + ) + } + #[test] + fn create_new_tree_with_from() { + // `BinaryTree::from` takes in a reference of an array because borrowing is sufficient + let tree = BinaryTree::from(&[1, 2, 3, 4, 5, 6]); + + assert_eq!( + tree, + BinaryTree::new(1) + .left(BinaryTree::new(2).left(BinaryTree::new(4)).right(BinaryTree::new(5))) + .right(BinaryTree::new(3).left(BinaryTree::new(6))) + ) + } +} + +/// A binary tree data structure. +#[derive(PartialEq, Debug)] +pub struct BinaryTree { + /// The value stored in the node. + pub value: T, + /// The left child of the node. + pub left: Option>>, + /// The right child of the node. + pub right: Option>>, +} + +impl BinaryTree +where + T: Copy + PartialEq, +{ + /// Creates a new binary tree node with the given value. + /// + /// # Arguments + /// + /// * `value` - The value to store in the node. + /// + /// # Returns + /// + /// A new binary tree node with the given value and no children. + pub fn new(value: T) -> Self { + BinaryTree { + value, + left: None, + right: None, + } + } + + /// Inserts a new value into the binary tree. + /// + /// The value is inserted into the first available position in the tree, + /// following a breadth-first traversal. + /// + /// # Arguments + /// + /// * `new_value` - The value to insert into the tree. + pub fn insert(&mut self, new_value: T) { + let mut queue: VecDeque<&mut BinaryTree> = VecDeque::new(); + queue.push_front(self); + + loop { + let BinaryTree { + ref mut left, + ref mut right, + .. + } = queue.pop_back().unwrap(); + + match left { + Some(node) => { + queue.push_front(node); + } + None => { + *left = Some(Box::new(BinaryTree::new(new_value))); + return; + } + } + + match right { + Some(node) => { + queue.push_front(node); + } + None => { + *right = Some(Box::new(BinaryTree::new(new_value))); + return; + } + } + } + } + + /// Creates a binary tree from a slice of values. + /// + /// The first value in the slice is used as the root of the tree, + /// and the remaining values are inserted into the tree in breadth-first order. + /// + /// # Arguments + /// + /// * `new_values` - A slice containing the values to insert into the tree. + /// + /// # Returns + /// + /// A binary tree containing the values from the input slice. + pub fn from(new_values: &[T]) -> Self { + let (first, rest) = new_values.split_first().unwrap(); + let mut root: BinaryTree = BinaryTree::new(*first); + + for value in rest { + root.insert(*value) + } + root + } + + /// Adds a left child to the current node. + /// + /// # Arguments + /// + /// * `node` - The binary tree node to add as the left child. + /// + /// # Returns + /// + /// A new binary tree node with the specified left child. + fn left(mut self, node: BinaryTree) -> Self { + self.left = Some(Box::new(node)); + self + } + + /// Adds a right child to the current node. + /// + /// # Arguments + /// + /// * `node` - The binary tree node to add as the right child. + /// + /// # Returns + /// + /// A new binary tree node with the specified right child. + fn right(mut self, node: BinaryTree) -> Self { + self.right = Some(Box::new(node)); + self + } +} diff --git a/src/data_structures.rs b/src/data_structures.rs index a3280bf..8b13789 100644 --- a/src/data_structures.rs +++ b/src/data_structures.rs @@ -1,224 +1 @@ -use std::collections::HashMap; -pub struct WeightedAdjacencyList { - vertices: HashMap>, -} - -impl Clone for WeightedAdjacencyList -where - T: Clone, - W: Clone, -{ - fn clone(&self) -> Self { - WeightedAdjacencyList { - vertices: self.vertices.clone(), - } - } -} - -impl WeightedAdjacencyList -where - T: std::hash::Hash + Eq + Clone, -{ - // Constructor to create a new weighted adjacency list - pub fn new() -> Self { - WeightedAdjacencyList { - vertices: HashMap::new(), - } - } - - // Method to add a vertex to the adjacency list - pub fn add_vertex(&mut self, vertex: T) { - self.vertices.entry(vertex).or_insert(HashMap::new()); - } - - // Method to add an edge with weight between two vertices - pub fn add_edge(&mut self, from: T, to: T, weight: W) { - // Ensure both vertices exist in the adjacency list - self.add_vertex(from.clone()); - self.add_vertex(to.clone()); - - // Add the edge from 'from' to 'to' with weight - self.vertices.get_mut(&from).unwrap().insert(to, weight); - } - - // Method to get the weight of an edge between two vertices - pub fn get_weight(&self, from: &T, to: &T) -> Option<&W> { - self.vertices.get(from)?.get(to) - } - - // Method to get the neighbors of a vertex - pub fn get_neighbors(&self, vertex: &T) -> Option<&HashMap> { - self.vertices.get(vertex) - } - // Method to get the number of vertices in the adjacency list - pub fn len(&self) -> usize { - self.vertices.len() - } -} - -/// A min-heap data structure for managing elements based on their order. -/// -/// This struct implements a min-heap, where the smallest element is always at the top. -/// It is generic over type `T`, which must implement the `PartialOrd` trait. -pub struct MinHeap { - data: Vec, -} - -impl MinHeap { - /// Creates a new, empty `MinHeap`. - /// - /// # Examples - /// - /// ``` - /// use min_heap::MinHeap; - /// - /// let mut heap: MinHeap = MinHeap::new(); - /// ``` - pub fn new() -> Self { - MinHeap { data: Vec::new() } - } - - /// Pushes an element onto the heap. - /// - /// # Arguments - /// - /// * `element` - The element to be pushed onto the heap. - /// - /// # Examples - /// - /// ``` - /// use min_heap::MinHeap; - /// - /// let mut heap: MinHeap = MinHeap::new(); - /// heap.push(5); - /// heap.push(3); - /// ``` - pub fn push(&mut self, element: T) { - self.data.push(element); - self.heapify_up(self.data.len() - 1); - } - - /// Pops the smallest element from the heap. - /// - /// This removes and returns the smallest element from the heap. - /// - /// # Returns - /// - /// The smallest element, if the heap is not empty. - /// - /// # Examples - /// - /// ``` - /// use min_heap::MinHeap; - /// - /// let mut heap: MinHeap = MinHeap::new(); - /// heap.push(5); - /// heap.push(3); - /// assert_eq!(heap.pop(), Some(3)); - /// ``` - pub fn pop(&mut self) -> Option { - if self.data.is_empty() { - return None; - } - let last_index = self.data.len() - 1; - self.data.swap(0, last_index); - let result = self.data.pop(); - self.heapify_down(0); - result - } - - /// Maintains the heap property by moving an element up. - /// - /// # Arguments - /// - /// * `index` - The index of the element to be moved up. - fn heapify_up(&mut self, mut index: usize) { - while index != 0 { - let parent_index = (index - 1) / 2; - if self.data[index] < self.data[parent_index] { - self.data.swap(parent_index, index); - } - index = parent_index; - } - } - - /// Maintains the heap property by moving an element down. - /// - /// # Arguments - /// - /// * `index` - The index of the element to be moved down. - fn heapify_down(&mut self, mut index: usize) { - let length = self.data.len(); - loop { - let left_child = 2 * index + 1; - let right_child = 2 * index + 2; - - let mut smallest = index; - - if left_child < length && self.data[left_child] < self.data[smallest] { - smallest = left_child; - } - - if right_child < length && self.data[right_child] < self.data[smallest] { - smallest = right_child; - } - - if smallest != index { - self.data.swap(index, smallest); - index = smallest; - } else { - break; - } - } - } -} -pub struct Queue { - queue: Vec, -} - -impl Queue { - pub fn new() -> Self { - Queue { queue: Vec::new() } - } - pub fn length(&self) -> usize { - self.queue.len() - } - pub fn enqueue(&mut self, item: T) { - self.queue.push(item) - } - pub fn dequeue(&mut self) -> T { - self.queue.remove(0) - } - pub fn is_empty(&self) -> bool { - self.queue.is_empty() - } - pub fn peek(&self) -> Option<&T> { - self.queue.first() - } -} - -pub struct Stack { - stack: Vec, -} - -impl Stack { - pub fn new() -> Self { - Stack { stack: Vec::new() } - } - pub fn length(&self) -> usize { - self.stack.len() - } - pub fn pop(&mut self) -> Option { - self.stack.pop() - } - pub fn push(&mut self, item: T) { - self.stack.push(item) - } - pub fn is_empty(&self) -> bool { - self.stack.is_empty() - } - pub fn peek(&self) -> Option<&T> { - self.stack.last() - } -} diff --git a/src/dijkstras.rs b/src/dijkstras.rs index 5cb0602..dd287eb 100644 --- a/src/dijkstras.rs +++ b/src/dijkstras.rs @@ -1,7 +1,8 @@ -use crate::data_structures::{WeightedAdjacencyList,MinHeap}; +use crate::weighted_adj_list::{WeightedAdjacencyList}; +use crate::min_heap::MinHeap; #[cfg(test)] mod tests { - use crate::data_structures::WeightedAdjacencyList; + use crate::weighted_adj_list::WeightedAdjacencyList; use super::dijkstras_shortest_path; #[test] fn dijkstras_shortest_path_primeagen_class_test(){ diff --git a/src/main.rs b/src/main.rs index c652b8b..abacd64 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,11 @@ mod binary_search; mod bubble_sort; mod quick_sort; mod dijkstras; +mod queue; +mod stack; +mod binary_tree; +mod min_heap; +mod weighted_adj_list; mod data_structures; fn linear_search_demo(){ println!("-------------------"); diff --git a/src/min_heap.rs b/src/min_heap.rs new file mode 100644 index 0000000..9bdb69b --- /dev/null +++ b/src/min_heap.rs @@ -0,0 +1,116 @@ +/// A min-heap data structure for managing elements based on their order. +/// +/// This struct implements a min-heap, where the smallest element is always at the top. +/// It is generic over type `T`, which must implement the `PartialOrd` trait. +pub struct MinHeap { + data: Vec, +} + +impl MinHeap { + /// Creates a new, empty `MinHeap`. + /// + /// # Examples + /// + /// ``` + /// use min_heap::MinHeap; + /// + /// let mut heap: MinHeap = MinHeap::new(); + /// ``` + pub fn new() -> Self { + MinHeap { data: Vec::new() } + } + + /// Pushes an element onto the heap. + /// + /// # Arguments + /// + /// * `element` - The element to be pushed onto the heap. + /// + /// # Examples + /// + /// ``` + /// use min_heap::MinHeap; + /// + /// let mut heap: MinHeap = MinHeap::new(); + /// heap.push(5); + /// heap.push(3); + /// ``` + pub fn push(&mut self, element: T) { + self.data.push(element); + self.heapify_up(self.data.len() - 1); + } + + /// Pops the smallest element from the heap. + /// + /// This removes and returns the smallest element from the heap. + /// + /// # Returns + /// + /// The smallest element, if the heap is not empty. + /// + /// # Examples + /// + /// ``` + /// use min_heap::MinHeap; + /// + /// let mut heap: MinHeap = MinHeap::new(); + /// heap.push(5); + /// heap.push(3); + /// assert_eq!(heap.pop(), Some(3)); + /// ``` + pub fn pop(&mut self) -> Option { + if self.data.is_empty() { + return None; + } + let last_index = self.data.len() - 1; + self.data.swap(0, last_index); + let result = self.data.pop(); + self.heapify_down(0); + result + } + + /// Maintains the heap property by moving an element up. + /// + /// # Arguments + /// + /// * `index` - The index of the element to be moved up. + fn heapify_up(&mut self, mut index: usize) { + while index != 0 { + let parent_index = (index - 1) / 2; + if self.data[index] < self.data[parent_index] { + self.data.swap(parent_index, index); + } + index = parent_index; + } + } + + /// Maintains the heap property by moving an element down. + /// + /// # Arguments + /// + /// * `index` - The index of the element to be moved down. + fn heapify_down(&mut self, mut index: usize) { + let length = self.data.len(); + loop { + let left_child = 2 * index + 1; + let right_child = 2 * index + 2; + + let mut smallest = index; + + if left_child < length && self.data[left_child] < self.data[smallest] { + smallest = left_child; + } + + if right_child < length && self.data[right_child] < self.data[smallest] { + smallest = right_child; + } + + if smallest != index { + self.data.swap(index, smallest); + index = smallest; + } else { + break; + } + } + } +} diff --git a/src/queue.rs b/src/queue.rs new file mode 100644 index 0000000..5c75891 --- /dev/null +++ b/src/queue.rs @@ -0,0 +1,24 @@ +pub struct Queue { + queue: Vec, +} + +impl Queue { + pub fn new() -> Self { + Queue { queue: Vec::new() } + } + pub fn length(&self) -> usize { + self.queue.len() + } + pub fn enqueue(&mut self, item: T) { + self.queue.push(item) + } + pub fn dequeue(&mut self) -> T { + self.queue.remove(0) + } + pub fn is_empty(&self) -> bool { + self.queue.is_empty() + } + pub fn peek(&self) -> Option<&T> { + self.queue.first() + } +} diff --git a/src/stack.rs b/src/stack.rs new file mode 100644 index 0000000..e8aca18 --- /dev/null +++ b/src/stack.rs @@ -0,0 +1,24 @@ +pub struct Stack { + stack: Vec, +} + +impl Stack { + pub fn new() -> Self { + Stack { stack: Vec::new() } + } + pub fn length(&self) -> usize { + self.stack.len() + } + pub fn pop(&mut self) -> Option { + self.stack.pop() + } + pub fn push(&mut self, item: T) { + self.stack.push(item) + } + pub fn is_empty(&self) -> bool { + self.stack.is_empty() + } + pub fn peek(&self) -> Option<&T> { + self.stack.last() + } +} diff --git a/src/weighted_adj_list.rs b/src/weighted_adj_list.rs new file mode 100644 index 0000000..16a199f --- /dev/null +++ b/src/weighted_adj_list.rs @@ -0,0 +1,58 @@ +use std::collections::HashMap; + +pub struct WeightedAdjacencyList { + vertices: HashMap>, +} + +impl Clone for WeightedAdjacencyList +where + T: Clone, + W: Clone, +{ + fn clone(&self) -> Self { + WeightedAdjacencyList { + vertices: self.vertices.clone(), + } + } +} + +impl WeightedAdjacencyList +where + T: std::hash::Hash + Eq + Clone, +{ + // Constructor to create a new weighted adjacency list + pub fn new() -> Self { + WeightedAdjacencyList { + vertices: HashMap::new(), + } + } + + // Method to add a vertex to the adjacency list + pub fn add_vertex(&mut self, vertex: T) { + self.vertices.entry(vertex).or_insert(HashMap::new()); + } + + // Method to add an edge with weight between two vertices + pub fn add_edge(&mut self, from: T, to: T, weight: W) { + // Ensure both vertices exist in the adjacency list + self.add_vertex(from.clone()); + self.add_vertex(to.clone()); + + // Add the edge from 'from' to 'to' with weight + self.vertices.get_mut(&from).unwrap().insert(to, weight); + } + + // Method to get the weight of an edge between two vertices + pub fn get_weight(&self, from: &T, to: &T) -> Option<&W> { + self.vertices.get(from)?.get(to) + } + + // Method to get the neighbors of a vertex + pub fn get_neighbors(&self, vertex: &T) -> Option<&HashMap> { + self.vertices.get(vertex) + } + // Method to get the number of vertices in the adjacency list + pub fn len(&self) -> usize { + self.vertices.len() + } +}