diff --git a/DIRECTORY.md b/DIRECTORY.md index 80305b42805..47a0f32158a 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -79,6 +79,7 @@ * [Trie](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/trie.rs) * [Union Find](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/union_find.rs) * [Veb Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/veb_tree.rs) + * [Linked List Queue]([https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/linked_list.rs](https://github.com/Ismael144/Rust-algorithms/blob/master/src/data_structures/queue_using_singly_linked_list.rs)) * Dynamic Programming * [Coin Change](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/coin_change.rs) * [Egg Dropping](https://github.com/TheAlgorithms/Rust/blob/master/src/dynamic_programming/egg_dropping.rs) diff --git a/src/data_structures/mod.rs b/src/data_structures/mod.rs index 621ff290360..64c81b8a830 100644 --- a/src/data_structures/mod.rs +++ b/src/data_structures/mod.rs @@ -10,6 +10,7 @@ mod lazy_segment_tree; mod linked_list; mod probabilistic; mod queue; +mod queue_using_singly_linked_list; mod range_minimum_query; mod rb_tree; mod segment_tree; @@ -34,6 +35,7 @@ pub use self::linked_list::LinkedList; pub use self::probabilistic::bloom_filter; pub use self::probabilistic::count_min_sketch; pub use self::queue::Queue; +pub use self::queue_using_singly_linked_list::LinkedListQueue; pub use self::range_minimum_query::RangeMinimumQuery; pub use self::rb_tree::RBTree; pub use self::segment_tree::SegmentTree; diff --git a/src/data_structures/queue_using_singly_linked_list.rs b/src/data_structures/queue_using_singly_linked_list.rs new file mode 100644 index 00000000000..22599db6a4f --- /dev/null +++ b/src/data_structures/queue_using_singly_linked_list.rs @@ -0,0 +1,448 @@ +//! This module is about a queue implemented using a singly linked list +//! +//! The queue follows FIFO (First-In First-Out) principle +//! The [enqueue] method's time complexity is O(1) +//! The [dequeue] method's time complexity is O(1) +//! The [insert] method's time complexity is O(n) +//! The [delete] method's time complexity is O(n) +//! The [peek_front] method's time complexity is O(1) +//! The [peek_back] method's time complexity is O(1) +//! The [len] method's time complexity is O(1) +//! The [is_empty] method's time complexity is O(1) +//! +//! I implemented Iterator, Default and Debug trait for our LinkedListQueue data structure +//! + +use std::fmt::Debug; +use std::marker::PhantomData; + +#[derive(Clone)] +struct Node { + element: T, + next: Option>>, +} + +impl Node { + fn new(element: T) -> Box { + Box::new(Self { + element, + next: None, + }) + } +} + +/// LinkedListQueue Implementation using Singly Linked List logic +#[derive(Clone)] +pub struct LinkedListQueue { + length: usize, + head: Option>>, + tail: Option>>, + // Act like we own the boxes or nodes, since we are gonna construct and mutate them + _marker: PhantomData>>, +} + +// Implementing default for our LinkedListQueue +impl Default for LinkedListQueue { + fn default() -> Self { + LinkedListQueue::new() + } +} + +// Implement iterator for the queue +pub struct LinkedListQueueIter<'a, T> { + current: &'a Option>>, + _marker: PhantomData<&'a T>, +} + +// Implementing Drop for LinkedListQueue +impl Drop for LinkedListQueue { + fn drop(&mut self) { + // Dequeue the queue until its empty + while self.dequeue().is_some() {} + } +} + +// Debug implementation for our LinkedListQueue +impl Debug for LinkedListQueue +where + T: Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "LinkedListQueue ( elements: [")?; + let mut is_first = true; + for elem in self.iter() { + if !is_first { + write!(f, ", ")?; + } + is_first = false; + write!(f, "{elem:?}")?; + } + write!(f, "], length: {} )", self.len()) + } +} + +// LinkedListQueueIterator implementation +impl<'a, T> Iterator for LinkedListQueueIter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + // Initially, current is set to the current tail, + // It will walk the tail when a user calls next + self.current.as_ref().map(|node| { + self.current = &node.next; + + &node.element + }) + } +} + +// Implementation for the queue +impl LinkedListQueue { + pub fn new() -> Self { + Self { + length: 0, + head: None, + tail: None, + _marker: PhantomData, + } + } + + // Iter method, will enably us to iterate through our queue + pub fn iter(&self) -> LinkedListQueueIter<'_, T> { + LinkedListQueueIter { + current: &self.tail, + _marker: PhantomData, + } + } + + /// The enqueue method, more of like the `push_back` of a linked list + pub fn enqueue(&mut self, element: T) + where + T: Clone, + { + // We create a new node + let mut new_node = Node::new(element); + // We make new_node's next to point to the old tail + new_node.next = self.tail.take(); + + // Here, we are setting the old_tail's next to point to the new pointer + if let Some(old_tail) = &mut self.tail { + old_tail.next = Some(Box::clone(&new_node)); + } + + // Making the new_node the tail + self.tail = Some(new_node.clone()); + + // If the list is empty, we first assign the new_node to the head before the tail + if self.head.is_none() { + self.head = Some(Box::clone(&new_node)); + } + + // Increment the length + self.length += 1; + } + + /// The `dequeue` method, more of like the `pop_front` method of a singly linked list + pub fn dequeue(&mut self) -> Option { + // We take the old head, and get next pointer the old head had been pointing to, we get that node, + // making it the new head + let result = self.tail.take().map(|mut old_tail| { + if let Some(next_node) = old_tail.next.take() { + self.tail = Some(next_node); + } + + if self.tail.is_none() { + self.head = None; + + // When the head is popped, the element is none, meaning + // it will not decrement length + // Check whether the length is zero, then the list is empty, so it will skip, else + // decrement 1 from the length + if !self.is_empty() { + self.length -= 1; + } + } + + old_tail.element + }); + + // If the list wasn't empty (or popped a node), decrement the length + // SAFETY: this will prevent the length from going below usize::MIN, because + // a user may try to dequeue an empty queue, which would lead to negatives + // which are not supported by the usize + if result.is_some() && !self.is_empty() { + self.length -= 1; + } + + result + } + + /// Reference to the first element in the queue + pub fn peek_front(&self) -> Option<&T> { + self.tail.as_ref().map(|tail| &tail.element) + } + + // Reference to value at the end of the queue + pub fn peek_back(&self) -> Option<&T> { + self.head.as_ref().map(|head| &head.element) + } + + // Get element by index from the queue + pub fn get(&self, index: usize) -> Option<&T> { + let mut counter = 0; + // If index == 0, it returns the first element from the queue, using the peek_front + if index == 0 { + return self.peek_front(); + + // if index is the last, then returns last element using peek_back + } else if index == (self.len() - 1) { + return self.peek_back(); + + // Else, returns none, if index is out of bounds + } else if index > (self.len() - 1) { + return None; + } + + let mut _current = &self.head; + let mut get_node: Option<&T> = None; + // If the node was not got we also index through the tail + if get_node.is_none() { + // Setting current to now be the tail + _current = &self.tail; + // And also reset counter to 0, because the head will have atmost 1 element + counter += 1; + + // We traverse to the node to get from the queue + while let Some(node) = &_current { + // If the selected index matches the pointer, then set get_node + // to node at that index + if counter == index { + get_node = Some(&node.element); + // Break the loop after getting the element at given index + break; + } + + // Increment counter + counter += 1; + + _current = &node.next; + } + } + + get_node + } + + /// Insert element at nth position in the queue + pub fn insert(&mut self, index: usize, element: T) + where + T: Clone, + { + // Initialize a new node + let mut new_node = Node::new(element.clone()); + + // If the index is greater the last index, then panic + if self.len() - 1 < index { + panic!("Trying to insert element to index out of bounds") + } + + // If the length is zero, then just insert at the tail + if self.is_empty() { + self.tail = Some(Box::clone(&new_node)); + } else { + // If length is greater than zero, we assign current to zero, initially + let mut current = self.tail.as_mut().unwrap(); + + // Create a for loop to end at the index selected by user, then assign + // the node at that index to current + // I made it (index - 1) so that it gets the previous node instead of the exact + // node inorder for current.next to point to the exact node, when it reaches the node + for _ in 0..index - 1 { + current = current.next.as_mut().unwrap(); + } + + // We set the new_node's next to be current next node + new_node.next.clone_from(¤t.next); + + // Increment the length + self.length += 1; + // Then we set the current's next node to point to the new_node + current.next = Some(new_node); + } + } + + pub fn delete(&mut self, index: usize) -> Option + where + T: Clone, + { + // Index out of bounds + if index >= self.length { + return None; + } + + if index == 0 { + // Deleting the head (equivalent to dequeue) + self.dequeue() + } else { + let mut current = self.tail.as_mut()?; + + // Traverse to the node just before the one to delete + for _ in 0..index - 1 { + current = current.next.as_mut()?; + } + + // The node to delete is current.next + let mut to_delete = current.next.take()?; // Take ownership of the node to delete + + // Re-link the current node to skip over the deleted node + current.next = to_delete.next.take(); + + // If the deleted node was the last node, update the tail pointer + if current.next.is_none() { + // If there is no next node, set tail to the current node + self.tail = Some(current.clone()); + } + + // Decrease the queue length + self.length -= 1; + + // Return the deleted element + Some(to_delete.element) + } + } + + /// Empty the queue + pub fn drain(&mut self) { + while self.dequeue().is_some() {} + } + + /// Gets the length of the queue + pub fn len(&self) -> usize { + self.length + } + + /// Check whether the queue is empty or not + pub fn is_empty(&self) -> bool { + self.length == 0 + } +} + +/// The queue implementation tests +#[cfg(test)] +mod tests { + use super::LinkedListQueue; + + #[test] + fn test_enqueue() { + // Creating a new queue + let mut queue = LinkedListQueue::::new(); + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert_eq!(queue.len(), 3); + } + + #[test] + fn test_dequeue() { + let mut queue = LinkedListQueue::::new(); + // Enqueue a couple of values + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + queue.enqueue(4); + + // Then dequeue some values + queue.dequeue(); + queue.dequeue(); + + assert_eq!(queue.len(), 2); + } + + #[test] + fn test_queue_length() { + let mut queue = LinkedListQueue::new(); + + // Enqueue a couple of elements + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert_eq!(queue.len(), 3); + } + + #[test] + fn test_peek_front() { + let mut queue = LinkedListQueue::default(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert_eq!(Some(&3), queue.peek_front()); + } + + #[test] + fn peek_back() { + let mut queue = LinkedListQueue::default(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + assert_eq!(Some(&1), queue.peek_back()); + } + + #[test] + fn test_get_from_queue() { + let mut queue = LinkedListQueue::new(); + queue.enqueue(2); + queue.enqueue(3); + queue.enqueue(5); + + let result = queue.get(1); + + assert!(result.is_some()); + } + + #[test] + fn test_queue_insert() { + let mut queue = LinkedListQueue::default(); + + queue.enqueue(1); + queue.enqueue(3); + queue.enqueue(4); + queue.insert(2, 2); + + assert_eq!(queue.len(), 4); + } + + #[test] + fn test_queue_delete() { + let mut queue = LinkedListQueue::default(); + + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + queue.delete(1); + + assert_eq!(queue.len(), 2); + // Whether to see whether an option of variant Some is returned + assert!(queue.delete(1).is_some()); + } + + #[test] + fn test_queue_drain() { + let mut queue = LinkedListQueue::default(); + + // Enqueue some elements + queue.enqueue(1); + queue.enqueue(2); + queue.enqueue(3); + + // Then drain the queue + queue.drain(); + + assert_eq!(queue.len(), 0); + } +}