Skip to main content

plain_ds/list/
sorted.rs

1use crate::core::Node;
2use crate::list::api::List;
3use crate::list::common::ListCommon;
4
5/// An ordered collection that maintains its elements in sorted order.
6///
7/// The `SortedList` automatically keeps elements sorted upon insertion,
8/// ensuring efficient search operations.
9///
10/// # Type Parameters
11/// * `T`: The type of elements stored in the list. Must implement `PartialOrd`.
12///
13/// # Examples
14/// ```
15/// use plain_ds::SortedList;
16///
17/// let mut list = SortedList::new();
18/// list.push(3);
19/// list.push(1);
20/// list.push(2);
21///
22/// assert_eq!(list.len(), 3);
23/// assert_eq!(list.to_vec(), vec![1, 2, 3]);
24/// ```
25pub struct SortedList<T> {
26    state: ListCommon<T>,
27}
28
29impl<T> SortedList<T> {
30    /// Creates empty ordered list.
31    pub fn new() -> Self {
32        Self {
33            state: ListCommon::new(),
34        }
35    }
36
37    /// Creates list from slice.
38    ///
39    /// Efficiency: O(n)
40    pub fn from_slice(slice: &[T]) -> Self
41    where
42        T: Clone + PartialOrd,
43    {
44        let mut list = SortedList::new();
45        for value in slice.iter() {
46            list.push((*value).clone());
47        }
48        list
49    }
50
51    /// Collect list values into a vector.
52    ///
53    /// Efficiency: O(n)
54    pub fn to_vec(&self) -> Vec<T>
55    where
56        T: Clone,
57    {
58        self.state.to_vec()
59    }
60
61    /// Finds the first node whose payload satisfies the predicate and returns its index.
62    /// Returns `None` if there is no such node.
63    ///
64    /// Efficiency: O(n)
65    pub fn find_if(&self, predicate: impl Fn(&T) -> bool) -> Option<usize>
66    where
67        T: PartialOrd,
68    {
69        self.state.find_if(predicate)
70    }
71
72    // Helper for insertion into the middle (used in push())
73    fn insert_in_middle(&mut self, ptr: *mut Node<T>)
74    where
75        T: PartialOrd,
76    {
77        let mut prev = self.state.head;
78        unsafe {
79            let mut next = (*prev).next;
80
81            while !next.is_null() {
82                if (*ptr).payload < (*next).payload {
83                    (*prev).next = ptr;
84                    (*ptr).next = next;
85                    return;
86                }
87                prev = next;
88                next = (*next).next;
89            }
90        }
91    }
92}
93
94impl<'a, T: 'a> List<'a, T> for SortedList<T>
95where
96    T: PartialOrd,
97{
98    /// Returns list size.
99    ///
100    /// Efficiency: O(1)
101    fn len(&self) -> usize {
102        self.state.len()
103    }
104
105    /// Returns the payload value of the first node in the list.
106    ///
107    /// Efficiency: O(1)
108    fn head(&self) -> Option<&T> {
109        self.state.head()
110    }
111
112    /// Returns the payload value of the last node in the list.
113    ///
114    /// Efficiency: O(1)
115    fn last(&self) -> Option<&T> {
116        self.state.last()
117    }
118
119    /// Returns an iterator over the immutable items of the list.
120    fn iter(&self) -> impl Iterator<Item = &'a T> {
121        self.state.iter()
122    }
123
124    /// Returns an iterator over the mutable items of the list.
125    fn iter_mut(&mut self) -> impl Iterator<Item = &'a mut T> {
126        self.state.iter_mut()
127    }
128
129    /// Returns an iterator that consumes the list.
130    fn into_iter(self) -> impl Iterator<Item = T> {
131        self.state.into_iter()
132    }
133
134    /// Adds a new node to the list according to the sort order.
135    ///
136    /// Efficiency: O(n) at worst
137    fn push(&mut self, payload: T) {
138        let ptr = Box::into_raw(Box::new(Node::new(payload)));
139
140        if self.is_empty() {
141            self.state.head = ptr;
142            self.state.last = ptr;
143        } else {
144            unsafe {
145                // Quick Case: Insert at the Beginning
146                if (*ptr).payload <= (*self.state.head).payload {
147                    (*ptr).next = self.state.head;
148                    self.state.head = ptr;
149                }
150                // Quick Case: Insert at the End
151                else if (*self.state.last).payload <= (*ptr).payload {
152                    (*self.state.last).next = ptr;
153                    self.state.last = ptr;
154                }
155                // General case: searching for a position in the middle
156                else {
157                    self.insert_in_middle(ptr);
158                }
159            }
160        }
161        self.state.size += 1;
162    }
163
164    /// Removes a node from the end of the list and returns its payload value.
165    ///
166    /// Efficiency: O(n)
167    fn pop_back(&mut self) -> Option<T> {
168        self.state.pop_back()
169    }
170
171    /// Removes a node from the front of the list and returns its payload value.
172    ///
173    /// Efficiency: O(1)
174    fn pop_front(&mut self) -> Option<T> {
175        self.state.pop_front()
176    }
177
178    /// Removes a node from the specified location in the list.
179    /// Error returns, if the index out of bounds.
180    ///
181    /// Efficiency: O(n)
182    fn remove(&mut self, index: usize) -> crate::Result<T> {
183        self.state.remove(index)
184    }
185
186    /// Finds the first node whose payload is equal to the given `value` and returns its index.
187    /// Returns `None` if there is no such node.
188    ///
189    /// Efficiency: O(n) at worst
190    fn find(&self, value: &T) -> Option<usize>
191    where T: PartialEq<T>
192    {
193        for (index, payload) in self.iter().enumerate() {
194            if payload == value {
195                return Some(index);
196            }
197            // Early exit: If the data is sorted and the current value
198            // is already greater than the possible match
199            if payload > value {
200                break; // definitely won't find anything further
201            }
202        }
203        None
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::*;
210
211    #[test]
212    fn test_from_slice() {
213        let list = SortedList::from_slice(&[2, 1, 5, 4, 3]);
214        assert_eq!(list.to_vec(), [1, 2, 3, 4, 5]);
215    }
216
217    mod push {
218        use std::cmp::Ordering;
219        use super::*;
220
221        #[test]
222        fn test_push_empty_list() {
223            let mut list = SortedList::<i32>::new();
224
225            list.push(42);
226
227            assert_eq!(list.len(), 1, "list should have one element after push");
228            assert_eq!(list.to_vec(), vec![42], "single element should be correctly inserted");
229            assert_eq!(list.state.head, list.state.last, "head and last should point to the same node in single-element list");
230        }
231
232        #[test]
233        fn test_push_to_beginning() {
234            let mut list = SortedList::from_slice(&[2, 3, 4]);
235
236            list.push(1);
237
238            let values = list.to_vec();
239            assert_eq!(values, vec![1, 2, 3, 4], "element smaller than all existing should be inserted at beginning");
240            unsafe {
241                assert_eq!((*list.state.head).payload, 1, "head should point to newly inserted smallest element");
242            }
243        }
244
245        #[test]
246        fn test_push_to_end() {
247            let mut list = SortedList::from_slice(&[1, 2, 3]);
248
249            list.push(4);
250
251            let values = list.to_vec();
252            assert_eq!(values, vec![1, 2, 3, 4], "element larger than all existing should be inserted at end");
253            unsafe {
254                assert_eq!((*list.state.last).payload, 4, "last should point to newly inserted largest element");
255            }
256        }
257
258        #[test]
259        fn test_push_in_middle() {
260            let mut list = SortedList::from_slice(&[1, 3, 5]);
261
262            list.push(2);
263
264            let values = list.to_vec();
265            assert_eq!(values, vec![1, 2, 3, 5], "element should be inserted in correct middle position");
266        }
267
268        #[test]
269        fn test_push_duplicate_values() {
270            let mut list = SortedList::from_slice(&[1, 3, 5]);
271
272            list.push(3);
273
274            let values = list.to_vec();
275            assert_eq!(values, vec![1, 3, 3, 5], "duplicate values should be inserted and preserved");
276        }
277
278        #[test]
279        fn test_push_multiple_elements_in_random_order() {
280            let mut list = SortedList::new();
281
282            // Insert elements in random order
283            list.push(5);
284            list.push(1);
285            list.push(3);
286            list.push(2);
287            list.push(4);
288
289            let values = list.to_vec();
290            assert_eq!(values, vec![1, 2, 3, 4, 5], "elements inserted in random order should result in sorted list");
291        }
292
293        #[test]
294        fn test_push_updates_size_correctly() {
295            let mut list = SortedList::new();
296
297            assert_eq!(list.len(), 0, "new list should have size 0");
298
299            list.push(1);
300            assert_eq!(list.len(), 1, "size should be 1 after first push");
301
302            list.push(2);
303            assert_eq!(list.len(), 2, "size should be 2 after second push");
304
305            list.push(0);
306            assert_eq!(list.len(), 3, "size should be 3 after third push");
307        }
308
309        #[test]
310        fn test_push_string_data() {
311            let mut list = SortedList::new();
312
313            list.push("zebra".to_string());
314            list.push("apple".to_string());
315            list.push("banana".to_string());
316
317            let values = list.to_vec();
318            assert_eq!(
319                values,
320                vec!["apple".to_string(), "banana".to_string(), "zebra".to_string()],
321                "strings should be sorted alphabetically"
322            );
323        }
324
325        #[test]
326        fn test_push_large_numbers() {
327            let mut list = SortedList::new();
328
329            list.push(1_000_000);
330            list.push(-1_000_000);
331            list.push(0);
332
333            let values = list.to_vec();
334            assert_eq!(values, vec![-1_000_000, 0, 1_000_000], "large positive and negative numbers should be sorted correctly");
335        }
336
337        #[test]
338        fn test_push_after_clear() {
339            let mut list = SortedList::from_slice(&[1, 2, 3]);
340            list.clear();
341
342            assert_eq!(list.len(), 0, "list should be empty after clear");
343
344            list.push(5);
345
346            let values = list.to_vec();
347            assert_eq!(values, vec![5], "push after clear should work correctly");
348            assert_eq!(list.len(), 1, "size should be 1 after push following clear");
349        }
350
351        #[test]
352        fn test_push_with_custom_ord_type() {
353            #[derive(Clone, Debug, PartialEq)]
354            struct Point {
355                x: i32,
356                y: i32,
357            }
358
359            impl PartialOrd for Point {
360                fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
361                    self.x.partial_cmp(&other.x)
362                }
363            }
364
365            let mut list = SortedList::new();
366            list.push(Point { x: 3, y: 1 });
367            list.push(Point { x: 1, y: 5 });
368            list.push(Point { x: 2, y: 8 });
369
370            let values = list.to_vec();
371            assert_eq!(values.len(), 3, "custom Ord type should be handled correctly");
372            assert_eq!(values[0].x, 1, "should be sorted by x coordinate");
373            assert_eq!(values[1].x, 2, "should be sorted by x coordinate");
374            assert_eq!(values[2].x, 3, "should be sorted by x coordinate");
375        }
376    }
377
378    mod find {
379        use super::*;
380
381        /// Helper function to create a list from a slice of values using from_slice
382        fn create_list_from_slice<T: Clone + PartialOrd>(values: &[T]) -> SortedList<T> {
383            SortedList::from_slice(values)
384        }
385
386        #[test]
387        fn test_find_empty_list() {
388            let list: SortedList<i32> = SortedList::new();
389            let result = list.find(&42);
390
391            assert_eq!(result, None, "should return None for empty list");
392        }
393
394        #[test]
395        fn test_find_element_at_beginning() {
396            let list = create_list_from_slice(&[1, 2, 3, 4, 5]);
397            let result = list.find(&1);
398
399            assert_eq!(result, Some(0), "should find element at index 0");
400        }
401
402        #[test]
403        fn test_find_element_in_middle() {
404            let list = create_list_from_slice(&[10, 20, 30, 40, 50]);
405            let result = list.find(&30);
406
407            assert_eq!(result, Some(2), "should find element in the middle and return correct index");
408        }
409
410        #[test]
411        fn test_find_element_at_end() {
412            let list = create_list_from_slice(&[5, 10, 15, 20]);
413            let result = list.find(&20);
414
415            assert_eq!(result, Some(3), "should find element at the end and return correct index");
416        }
417
418        #[test]
419        fn test_find_non_existent_element_smaller_than_all() {
420            let list = create_list_from_slice(&[10, 20, 30, 40]);
421            let result = list.find(&5);
422
423            assert_eq!(result, None, "should return None when searching for element smaller than all elements");
424        }
425
426        #[test]
427        fn test_find_non_existent_element_larger_than_all() {
428            let list = create_list_from_slice(&[10, 20, 30, 40]);
429            let result = list.find(&50);
430
431            // Early exit should trigger here — first check fails, then payload > value → break
432            assert_eq!(result, None, "should return None and use early exit for element larger than all");
433        }
434
435        #[test]
436        fn test_find_non_existent_element_between_values() {
437            let list = create_list_from_slice(&[10, 20, 30, 40]);
438            let result = list.find(&25);
439
440            // Should stop at 30 (30 > 25) without checking 40
441            assert_eq!(result, None, "should use early exit when value would be between existing elements");
442        }
443
444        #[test]
445        fn test_find_first_occurrence_of_duplicate() {
446            let list = create_list_from_slice(&[1, 2, 2, 3, 2]);
447            let result = list.find(&2);
448
449            assert_eq!(result, Some(1), "should return index of first occurrence when duplicates exist");
450        }
451
452        #[test]
453        fn test_find_single_element_match() {
454            let list = create_list_from_slice(&[42]);
455            let result = list.find(&42);
456
457            assert_eq!(result, Some(0), "should find matching element in single-element list");
458        }
459
460        #[test]
461        fn test_find_single_element_no_match() {
462            let list = create_list_from_slice(&[42]);
463            let result = list.find(&100);
464
465            assert_eq!(result, None, "should return None in single-element list when no match");
466        }
467
468        #[test]
469        fn test_find_with_string_data() {
470            let strings = vec!["apple", "banana", "cherry", "date"];
471            let list = create_list_from_slice(&strings);
472
473            let result = list.find(&"cherry");
474            assert_eq!(result, Some(2), "should find string element at correct index");
475
476            let result2 = list.find(&"grape");
477            assert_eq!(result2, None, "should return None for non‑existent string");
478        }
479
480        #[test]
481        fn test_find_early_exit_efficiency_hint() {
482            // Large sorted list
483            let large_values: Vec<i32> = (0..1000).map(|x| x * 2).collect(); // 0, 2, 4, ..., 1998
484            let list = create_list_from_slice(&large_values);
485
486            // Search for value that doesn't exist but would be early in the list
487            let result = list.find(&1); // Should exit immediately at 0 (0 > 1 is false, but 2 > 1 → true → break)
488
489            assert_eq!(result, None, "should efficiently exit early when value is between first elements");
490
491            // Verify it didn't scan the whole list
492            // The early exit should happen after checking first few elements
493        }
494
495        #[test]
496        fn test_find_custom_type() {
497            #[derive(PartialEq, PartialOrd, Debug, Clone)]
498            struct Person {
499                name: String,
500                age: u32,
501            }
502
503            let people = vec![
504                Person { name: "Alice".to_string(), age: 25 },
505                Person { name: "Bob".to_string(), age: 30 },
506                Person { name: "Charlie".to_string(), age: 35 },
507            ];
508            let list = create_list_from_slice(&people);
509
510            let target = Person { name: "Bob".to_string(), age: 30 };
511            let result = list.find(&target);
512            assert_eq!(result, Some(1), "should find custom type by full equality");
513
514            let nonexistent = Person { name: "David".to_string(), age: 40 };
515            let result2 = list.find(&nonexistent);
516            assert_eq!(result2, None, "should return None for non‑existent custom type");
517        }
518
519        #[test]
520        fn test_find_preserves_list_integrity() {
521            let values = vec![1, 3, 5, 7, 9];
522            let list = create_list_from_slice(&values);
523
524            // Store original state
525            let original_vec = list.to_vec();
526
527            // Perform find operations
528            let _result1 = list.find(&3);
529            let _result2 = list.find(&6); // doesn't exist
530            let _result3 = list.find(&9);
531
532            // Verify list hasn't been modified
533            assert_eq!(list.to_vec(), original_vec, "find operation should not modify the original list");
534            assert_eq!(list.len(), 5, "list length should remain unchanged after find operations");
535        }
536
537        #[test]
538        fn test_find_on_list_with_negative_numbers() {
539            let list = create_list_from_slice(&[-10, -5, 0, 5, 10]);
540
541            assert_eq!(list.find(&-5), Some(1), "should find negative number at correct index");
542            assert_eq!(list.find(&0), Some(2), "should find zero at correct index");
543            assert_eq!(list.find(&15), None, "should return None for value larger than all elements");
544            assert_eq!(list.find(&-15), None, "should return None for value smaller than all elements");
545        }
546    }
547}