mini_linked_list/lib.rs
1//! # Linked List
2//!
3//! Implements a simple linked list using Heap memory.
4//! Currently, there's an implementation only for the i32 primitive type.
5pub struct LinkedList<T> {
6 pub val: Option<T>,
7 pub next: Option<Box<LinkedList<T>>>,
8}
9pub struct PopLeftResult<T> {
10 pub val: Option<T>,
11 pub list: Option<Box<LinkedList<T>>>
12}
13
14impl LinkedList<i32> {
15 /// # Creates an empty LinkedList that may hold i32 values
16 ///
17 /// # Example
18 /// ```
19 /// let list = mini_linked_list::LinkedList::<i32>::new();
20 /// ```
21 pub fn new() -> LinkedList<i32>{
22 LinkedList {
23 val: None,
24 next: None,
25 }
26 }
27 /// # Adds an element to the right side of the list
28 ///
29 /// This method uses O(N) operations, as it needs to traverse
30 /// the entire list before appending the new value to the end of the list.
31 ///
32 /// # Example
33 /// ```
34 /// let mut list = mini_linked_list::LinkedList::<i32>::new();
35 /// list.push_right(1);
36 /// list.push_right(2);
37 /// list.push_right(3);
38 /// list.push_right(4);
39 /// assert_eq!(list.collect(), vec![1,2,3,4]);
40 /// ```
41 pub fn push_right(&mut self, x: i32) {
42 let mut node = self;
43 while node.next.is_some() {
44 node = node.next.as_mut().unwrap();
45 }
46 node.next = Some(Box::new(LinkedList{
47 val: Some(x),
48 next: None,
49 }))
50 }
51 /// # Adds an element to the left side of the list
52 ///
53 /// This method works in O(1) operation, as it replaces the head of the list
54 /// with a new one and no traversal thus is required.
55 ///
56 /// The method returns the new memory address of the list that must be handled
57 /// by the caller (typically reassigning the variable).
58 ///
59 /// # Example
60 /// ```
61 /// use mini_linked_list::LinkedList;
62 /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
63 /// list = list.push_left(1);
64 /// list = list.push_left(2);
65 /// list = list.push_left(3);
66 /// list = list.push_left(4);
67 /// assert_eq!(list.collect(), vec![4,3,2,1]);
68 /// ```
69 pub fn push_left(self, x: i32) -> LinkedList<i32>{
70 let node= LinkedList::<i32> {
71 val: Some(x),
72 next: Some(Box::new(self))
73 };
74 node
75 }
76
77 /// # Pops the List head on the left side, returning a PopLeftResult
78 ///
79 /// This operation works in O(1), as it only pops the head and
80 /// no traversal is required.
81 ///
82 /// It's usage is not so straightforward, however, as it requires
83 /// the caller to replace the reference to the list head with the
84 /// address returned by this method, inside `PopLeftResult.list`
85 ///
86 /// It's advised to not call `unwrap` directly in `PopLeftResult.list``
87 /// directly, but rather rely on safer `Option` methods.
88 ///
89 /// # Example
90 ///
91 /// ```
92 /// use mini_linked_list::{LinkedList, PopLeftResult};
93 /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
94 /// list.push_right(1);
95 /// list.push_right(2);
96 ///
97 /// let result: PopLeftResult<i32> = list.pop_left();
98 /// let list = result.list.unwrap();
99 ///
100 /// assert_eq!(list.collect(), vec![2]);
101 /// assert_eq!(result.val.unwrap(), 1);
102 ///
103 /// let result: PopLeftResult<i32> = list.pop_left();
104 /// let list = result.list;
105 ///
106 /// assert_eq!(list.is_none(), true);
107 /// assert_eq!(result.val.unwrap(), 2);
108 /// ```
109
110 pub fn pop_left(self) -> PopLeftResult<i32> {
111 if self.val.is_some() {
112 return PopLeftResult { val: self.val, list: self.next }
113 }
114 match self.next {
115 Some(node) => PopLeftResult { val: node.val, list: node.next },
116 None => PopLeftResult { val: self.val, list: None }
117 }
118 }
119
120 /// # Pops the List head on the right side.
121 ///
122 /// This operation works in O(N), as it requires a full traversal
123 /// of the list.
124 ///
125 /// Whenever possible, prefer relying on the `pop_left` method, as it is more
126 /// efficient.
127 ///
128 /// # Example
129 ///
130 /// ```
131 /// use mini_linked_list::LinkedList;
132 /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
133 /// list.push_right(1);
134 /// list.push_right(2);
135 /// assert_eq!(list.pop_right().unwrap(), 2);
136 /// assert_eq!(list.pop_right().unwrap(), 1);
137 /// assert_eq!(list.pop_right().is_none(), true);
138 /// ```
139 pub fn pop_right(&mut self) -> Option<i32>{
140 let mut node: &mut Option<Box<LinkedList<i32>>> = &mut self.next;
141 let x: Option<i32>;
142 // no next node, need to try to pop self
143 if node.is_none() {
144 let val = self.val;
145 self.val = None;
146 return val
147 }
148 // only one next node, we should return it
149 if node.as_mut().unwrap().next.is_none() {
150 x = node.as_mut().unwrap().val;
151 node.as_mut().unwrap().next = None;
152 node.as_mut().unwrap().val = None;
153 return x;
154 }
155 // we can assume we have at least two valid next aheads
156 else {
157 while node.as_mut().unwrap().next.as_mut().unwrap().next.is_some() {
158 node = &mut node.as_mut().unwrap().next;
159 }
160 x = node.as_mut().unwrap().next.as_mut().unwrap().val;
161 node.as_mut().unwrap().next = None;
162 }
163 return x
164 }
165
166 /// # Collects the list into an Array
167 ///
168 /// This method is used mostly for debugging and testing,
169 /// but can also be used to iterate over the list without popping
170 /// it's values.
171 ///
172 /// It's not memory efficient, however, as it copies the entire
173 /// data.
174 ///
175 /// # Example
176 /// ```
177 /// use mini_linked_list::LinkedList;
178 /// let mut list: LinkedList<i32> = LinkedList::<i32>::new();
179 /// list.push_right(1);
180 /// list.push_right(2);
181 /// assert_eq!(list.collect(), vec![1,2]);
182 /// ```
183 pub fn collect(&self) -> Vec<i32> {
184 let mut result = Vec::<i32>::new();
185 let mut node = self;
186
187 match node.val {
188 Some(val) => result.push(val),
189 _ => ()
190 }
191 while node.next.is_some() {
192 node = node.next.as_ref().unwrap();
193 match node.val {
194 Some(val) => result.push(val),
195 _ => ()
196 }
197 }
198
199 return result;
200
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 #[test]
209 fn test_linked_list_push_right() {
210 let mut list: LinkedList<i32> = LinkedList::<i32>::new();
211 list.push_right(1);
212 list.push_right(2);
213 list.push_right(3);
214 list.push_right(4);
215 assert_eq!(list.collect(), vec![1,2,3,4]);
216 }
217 #[test]
218 fn test_linked_list_push_left() {
219 let mut list: LinkedList<i32> = LinkedList::<i32>::new();
220 list = list.push_left(1);
221 list = list.push_left(2);
222 list = list.push_left(3);
223 list = list.push_left(4);
224 assert_eq!(list.collect(), vec![4,3,2,1]);
225 }
226
227 #[test]
228 fn test_linked_list_pop_left() {
229 let mut list: LinkedList<i32> = LinkedList::<i32>::new();
230 list.push_right(1);
231 list.push_right(2);
232 list.push_right(3);
233 list.push_right(4);
234
235 let result = list.pop_left();
236 let list = result.list.unwrap();
237
238 assert_eq!(list.collect(), vec![2,3,4]);
239 assert_eq!(result.val.unwrap(), 1);
240
241 let result = list.pop_left();
242 let list = result.list.unwrap();
243
244 assert_eq!(list.collect(), vec![3,4]);
245 assert_eq!(result.val.unwrap(), 2);
246
247 let result = list.pop_left();
248 let list = result.list.unwrap();
249
250 assert_eq!(list.collect(), vec![4]);
251 assert_eq!(result.val.unwrap(), 3);
252
253 let result = list.pop_left();
254 assert_eq!(result.list.is_none(), true);
255 assert_eq!(result.val.unwrap(), 4);
256
257 }
258
259 #[test]
260 fn test_linked_list_pop_right() {
261 let mut list: LinkedList<i32> = LinkedList::<i32>::new();
262 list.push_right(1);
263 list.push_right(2);
264 list.push_right(3);
265 list.push_right(4);
266
267 assert_eq!(list.pop_right().unwrap(), 4);
268 assert_eq!(list.pop_right().unwrap(), 3);
269 assert_eq!(list.pop_right().unwrap(), 2);
270 assert_eq!(list.pop_right().unwrap(), 1);
271 assert_eq!(list.pop_right().is_none(), true);
272 }
273
274 #[test]
275 fn test_several_apis() {
276 let mut list: LinkedList<i32> = LinkedList::<i32>::new();
277 list.push_right(1);
278 list.push_right(2);
279 list.push_right(3);
280 list.push_right(4);
281 assert_eq!(list.collect(), vec![1,2,3,4]);
282
283 list = list.push_left(1);
284 list = list.push_left(2);
285 list = list.push_left(3);
286 list = list.push_left(4);
287 assert_eq!(list.collect(), vec![4,3,2,1,1,2,3,4]);
288 let x = list.pop_right();
289 assert_eq!(x.unwrap(), 4);
290 assert_eq!(list.collect(), vec![4,3,2,1,1,2,3]);
291
292 let result = list.pop_left();
293 let list = result.list.unwrap();
294 assert_eq!(list.collect(), vec![3,2,1,1,2,3]);
295 assert_eq!(result.val.unwrap(), 4);
296
297 }
298}