dsa_rust/sequences/
singly_linked_list.rs

1/*! A safe, owned, singly-linked list
2
3# About
4The primary goal with this implementation is to offer a simple linked list with no `unsafe` code. The list does this with `Box`-type pointers to owned, heap-allocated objects.
5
6#### Design
7This exceedingly simple, safe, singly-linked list consists of one primary [LinkedList] struct that provides stack and queue operations.
8
9The list operates on a single, private `Node` struct that contains only a `data` field (generic over `T`) and a `next` pointer as `Option<Box<Node<T>>>`. Due to the owned nature of the pointers and safe-code-only design restriction, _it is not possible to sort this list in place_.
10
11#### Iterators
12This list does not have any positional implementation, meaning that you cannot get pointers to arbitrary nodes within the list. The list _does_ provide an `iter()` method that yields an iterator over immutable references to `Node` data, consistent with Rust naming convention. Providing an `iter_mut()` that yields mutable references to the underlying `Node` data in safe Rust is currently beyond the scope of this structure. See the [doubly-linked variant](crate::sequences::doubly_linked_list) which uses a `CursorMut` API for mutable references to `Node` data.
13
14**TODO**:
15- Implement add/remove operations at arbitrary "indexes" (non-positional)
16
17# Examples
18
19This example illustrates stack (FILO) operations
20```rust
21    use dsa_rust::sequences::singly_linked_list::LinkedList;
22
23    let mut list: LinkedList<char> = LinkedList::new();
24
25    list.push('c');
26    list.push('b');
27    list.push('a'); // list: a, b, c
28
29    for e in list.iter() {
30        println!("{e}")
31    }
32
33    // Tests that the head is really the head
34    assert_eq!(list.peek().unwrap(), &'a');
35    assert_eq!(list.pop().unwrap(), 'a'); // list: b, c
36
37    list.push('d'); // list: d, b, c
38
39    list.pop(); // list: b, c
40    list.pop(); // list: c
41    assert_eq!(list.peek().unwrap(), &'c');
42    assert_eq!(list.pop().unwrap(), 'c'); // list: None
43
44    assert_eq!(list.peek(), None); // Looks like theres None left
45    assert_eq!(list.pop(), None); // dont wanna unwrap() on None!
46```
47
48<br>
49
50This example illustrates queue (FIFO) operations
51```rust
52    use dsa_rust::sequences::singly_linked_list::LinkedList;
53
54    let mut list: LinkedList<char> = LinkedList::new();
55
56    list.enqueue('a');
57    list.enqueue('b');
58    list.enqueue('c'); // list: a, b, c
59
60    // Tests that the head is really the head
61    assert_eq!(list.peek().unwrap(), &'a');
62    assert_eq!(list.dequeue().unwrap(), 'a'); // list: b, c
63
64    list.enqueue('d'); // list: b, c, d
65
66    list.dequeue(); // list: c, d
67    list.dequeue(); // list: d
68    assert_eq!(list.peek().unwrap(), &'d');
69    assert_eq!(list.dequeue().unwrap(), 'd'); // list: None
70
71    assert_eq!(list.peek(), None); // Looks like theres None left
72    assert_eq!(list.dequeue(), None); // dont wanna unwrap() on None!
73
74```
75
76<br>
77
78This example illustrates a sorting workaround
79```rust
80    use dsa_rust::sequences::singly_linked_list::LinkedList;
81
82    // 1) Create a new list of u8 values
83    let mut list: LinkedList<u8> = LinkedList::new();
84
85    // 2) (Add elements to the list)
86
87    // 3) Push the list to an easily-sortable structure
88    let mut data: Vec<_> = list.iter().cloned().collect();
89
90    // 4) Sort the Vec in O(n log n) time
91    data.sort();
92
93    // 5) Reconstruct the list as a sorted variant
94    let mut sorted_list = LinkedList::new();
95    for node in data {
96        //
97        // Use push() to create list in descending order
98        // Use enqueue() to create list in ascending order
99        sorted_list.enqueue(node);
100    }
101```
102*/
103
104struct Node<T> {
105    data: T,
106    next: Option<Box<Node<T>>>,
107}
108impl<T> Node<T> {
109    // Creates a new Node with an optional next pointer
110    fn new(data: T, next: Option<Box<Node<T>>>) -> Node<T> {
111        Node { data, next }
112    }
113
114    // Returns owned data from the node
115    fn take(self) -> T {
116        self.data
117    }
118
119    // Returns a reference to the data in a node
120    fn _peek(&self) -> &T {
121        &self.data
122    }
123
124    // Returns a reference to the data at the node's next pointer, if Some
125    fn _peek_next(&self) -> Option<&T> {
126        let next = &self.next;
127        if let Some(node) = next {
128            Some(&node.data)
129        } else {
130            None
131        }
132    }
133}
134
135/** The ❤️ of the module */
136pub struct LinkedList<T> {
137    head: Option<Box<Node<T>>>,
138    length: usize,
139}
140impl<T: Clone> Default for LinkedList<T> {
141    fn default() -> Self {
142        Self::new()
143    }
144}
145impl<T: Clone> LinkedList<T> {
146    /// Creates a new list
147    pub fn new() -> LinkedList<T> {
148        LinkedList {
149            head: None,
150            length: 0,
151        }
152    }
153
154    /** Adds a node to the head of the list/stack */
155    pub fn push(&mut self, data: T) {
156        // Create a new Node
157        let new_node = Node::new(data, self.head.take());
158
159        // Set the list's head to the new node
160        self.head = Some(Box::from(new_node));
161
162        // Increase the list's length
163        self.length += 1;
164    }
165
166    /** Removes/returns the head of the list/stack (if Some) in O(1) time */
167    pub fn pop(&mut self) -> Option<T> {
168        Self::remove_front(self)
169    }
170
171    /** Adds a node to the tail of the list/queue in O(n) time;
172
173    TODO: Safely implement a way to store a reference to the last node in the
174    list for O(1) enqueue operations */
175    pub fn enqueue(&mut self, data: T) {
176        // Wraps the data in an Option<Box<Node>>
177        let new_node = Some(Box::from(Node::new(data, None)));
178
179        // If the queue is empty, set `self.head` to the new node;
180        // Otherwise, traverse to the end of the queue and add the new node
181        if self.head.is_none() {
182            self.head = new_node;
183        } else {
184            let mut iter_node = &mut self.head;
185            while let Some(ref mut peek) = iter_node {
186                if peek.next.is_none() {
187                    peek.next = new_node;
188                    break;
189                }
190                iter_node = &mut peek.next;
191            }
192        }
193        self.length += 1;
194    }
195
196    /** Removes/returns the head of the list (if Some) in O(1) time */
197    //pub fn dequeue(&mut self) -> Option<Node<T>> {
198    pub fn dequeue(&mut self) -> Option<T> {
199        Self::remove_front(self)
200    }
201
202    /** Returns a reference to the head of the list (if Some) in O(1) time */
203    pub fn peek(&self) -> Option<&T> {
204        //if let Some(s) = &(*self).head {
205        //    Some(&s.data)
206        //} else {
207        //    None
208        //}
209        self.head.as_ref().map(|node| &node.data)
210    }
211
212    /** The meat and potatoes behind both pop() and dequeue() */
213    fn remove_front(&mut self) -> Option<T> {
214        if let Some(mut boxed_node) = self.head.take() {
215            self.head = boxed_node.next.take();
216            self.length -= 1;
217            let n = *boxed_node;
218            Some(n.take())
219        } else {
220            None
221        }
222    }
223
224    /** Returns an iterator of references to data in the list's nodes */
225    pub fn iter(&self) -> Iter<'_, T> {
226        Iter {
227            next: self.head.as_deref(),
228        }
229    }
230}
231
232pub struct Iter<'a, T> {
233    next: Option<&'a Node<T>>,
234}
235impl<'a, T> Iterator for Iter<'a, T> {
236    type Item = &'a T;
237
238    fn next(&mut self) -> Option<Self::Item> {
239        if let Some(current) = self.next {
240            self.next = current.next.as_deref(); // Move to next node
241            Some(&current.data) // Return reference to data
242        } else {
243            None
244        }
245    }
246}
247
248#[test]
249fn singly_linked_list_sort() {
250    let mut list: LinkedList<u8> = LinkedList::new();
251
252    // Creates a list by pushing elements to the head
253    list.push(4);
254    list.push(34);
255    list.push(46);
256    list.push(196);
257    list.push(98);
258    list.push(3);
259    list.push(77);
260    list.push(163); // Current head
261
262    // Pushes the list to a sortable structure
263    let mut data: Vec<_> = list.iter().cloned().collect();
264    data.sort(); // Defaults to ascending order
265
266    // Reconstructs the list as a sorted variant
267    let mut sorted_list = LinkedList::new();
268    for node in data {
269        // Use push() to create list in descending order
270        // Use enqueue() to create list in ascending order
271        sorted_list.enqueue(node);
272    }
273
274    // Print debug blocks
275    print!("unsorted list: ");
276    for e in list.iter() {
277        eprint!("{e}, ")
278    }
279    print!("\nsorted list: ");
280    for e in sorted_list.iter() {
281        eprint!("{e}, ")
282    }
283    //assert!(false); // Uncomment for cheap print debug trigger
284
285    assert_eq!(list.peek().unwrap(), &163); // head of unsorted list
286    assert_eq!(sorted_list.peek().unwrap(), &3); // head of sorted list
287}
288
289pub fn example() {
290    //TODO
291}