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(¤t.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}