dsa_rust/sequences/
indexed_skip_list.rs

1/*! A safe, indexed skip list
2
3# About
4Skip lists are sorted, probabalistic structures made up of logically stacked lists of varying length to allow for truncated _O(log(n))_ navigation. Canonically linked lists are built from doubly-linked lists, but this is not a defining characteristic of the ADT. Regardless of the base list representation used, the navigational algorithm results in what is essentially a logical linked list.
5
6Properly implemented skip lists provide _O(log(n))_ expected time complexity for search, insert, and removal operations. This provides a significant advantage over keeping sorted array- or link-based list invariants, which have _worst-case O(n)_ removal (average _O(n/2)_) temporal performance. Skip lists are also simpler than self-balancing tree structures, which are commonly used for sorted list and map structures. Skip lists also generally provide easier and finer-grained control when adapted for concurrent operations. There is a reason Java's `concurrentSkipListMap` is so popular.
7
8# Design
9This design uses `Vec`-backed storage for [SkipNode]s that contain a list (tower) of "next" values, and a single "previous" value that represent indexes within the backing vector.
10
11The list features a dynamic max height _h_ that is logarithmically proportional to the number of elements in the list _n_ such that _h = log(n) in the expected case_. The logarithmic growth ensures that the average search, insertion, and deletion operations remain efficient, typically with expected _O(log(n))_ time complexity.
12
13William Pugh's <a href="https://15721.courses.cs.cmu.edu/spring2018/papers/08-oltpindexes1/pugh-skiplists-cacm1990.pdf" target="_blank" rel="noopener noreferrer">original paper</a> from 1990 conveniently spells out random level, search, insert, and remove operations as pseudocode that is used to guide this module's design. Note that the pseudocode is modified from the original paper to fit the notation convention present in this module (that is, CLRS-style with ASCII characters), but is otherwise unchanged from the original paper.
14
15## The Search Algorithm
16The search algorithm as its presented in the original paper generalizes some _public-facing operation_ for list search which returns either the node representing the `value` associated with a `search_key` or a failure/nil/None value to indicate that the `search_key` is not in the list. 
17```text
180    Search(list, search_key)
191      x = list.header
202      // loop invariant: x.key < search_key
213      for i = list.level downto 1 do
224        while x.forward[i].key < search_key do
235          x = x.forward[i]
246      // x.key < search_key <= x.forward[1].key
257      x = x.forward[1]
268      if x.key == search_key then return x.value
279        else return failure
28```
29It makes sense to split this algorithm into two different pieces, roughly separated at line 5. In this implementation, the first part represents a private search operation `skip_search(e)` that returns a position that is strictly < `search_key`. This sub-routine is then re-used by the `get(e)`, `contains(e)`, `insert(e)`, and `remove(e)` operations. If the list is empty, `skip_search(e)` returns `0`. An empty list contains a single sentinel node, so there is _always_ a previous node to insert a value, even if its the sentinel.
30
31The second part of the algorithm simply represents a forward iteration and an equality check with the supplied `search_key`. This second phase is represented in a public `get(e)` operation that returns the value associated with the `search_key`, if it exists in the list. The equality check is crucial to determine whether the "next" node is actually the one being searched for.
32
33## Insertion & Removal Algorithms
34The insertion and deletion algorithms re-use much of the search algorithm's first phase, so they can be abstracted into [SkipList::skip_search] operations which return the node that is strictly smaller than the "search_key", which in this case is a new entry. The rest of the algorithm creates a new `SkipNode`, generates the "tower" len with a random number generator, populates the next node array for each level, and sets a singular previous node position.
35The 
36```text
37 0    Insert(list, search_key, newValue)
38 1      local update[1..MaxLevel]
39 2      x = list.header
40 3      for i = list.level downto 1 do
41 4        while x.forward[i].key < search_key do
42 5          x = x.forward[i]
43 6        // x.key < search_key <= x.forward[i].key
44 7        update[i] = x
45
46 8      x = x.forward[1]
47 9      if x.key = search_key then x.value = newValue
4810      else
4911        lvl = randomLevel()
5012        if lvl > list.level then
5113          for i = list.level + 1 to lvl do
5214            update[i] = list.header
5315          list.level = lvl
5416        x = makeNode(lvl, search_key, value)
5517        for i = 1 to level do
5618          x.forward[i] = update[i].forward[i]
5719          update[i].forward[i] = x
58```
59
60This structure uses a contiguous backing structure instead of stable pointers/Position objects. As a result the list cannot strictly maintain the original design's asymptotics. The major advantage of linked lists is _O(1)_ node insertion/removal if a handle exists to the node. Contiguous lists generally require either _O(n)_ moves for insertion/removal of arbitrary elements. However, there are two options to deal with this; either use a [Vec::swap_remove] operation for _O(1)_ removals without wasting space, or using a free list to identify and fill holes after removal. For simplicity, this structure uses the first approach, meaning that indexes are _not_ stable, and as such are not surfaced in the public API. This design keeps the space requirements in check, but changes the canonical _O(log(n))_ removal time to _O(n * height)_, which is _O(n * log(n)) expected_, and _O(n^2)_ worst case (even though the list's height is technically capped).
61
62Pugh's original removal algorithm (which is altered slightly in this implementation):
63```text
64 0    Delete(list, search_key)
65 1      local update[1..MaxLevel]
66 2      x = list.header
67 3      for i = list.level downto 1 do
68 4        while x.forward[i].key < search_key do
69 5          x = x.forward[i]
70 6        update[i] = x
71 7      x = x.forward[1]
72 8      if x.key = search_key then
73 9        for i = 1 to list.level do
7410          if update[i].forward[i] != x then break
7511          update[i].forward[i] = x.forward[i]
7612        free(x)
7713        while list.level > 1 and
7814          list.header.forward[list.level] == NIL do
7915          list.level = list.level – 1
80```
81The `remove(e)` as it exists in this module:
82```text
83 0    Delete(list, searchKey)
84 
85 1      local update[0..MaxLevel] = FindPredecessors(list, searchKey)
86 2      target = update[0].forward[0]
87 
88 3      // Early return for elements not in the list
89 4      if target = NIL or target.key != searchKey then
90 5        return failure
91 6      last = list.nodes.last
92
93 7      // unlink from skip structure
94 8      for i = 0 to list.level - 1 do
95 9        if update[i].forward[i] = target then
9610          update[i].forward[i] = target.forward[i]
97
9811      if target.forward[0] != NIL then
9912        target.forward[0].prev = target.prev
100
10113      removed = swap_remove(list.nodes, target)
102
10314      // fix relocated node (if any)
10415      if target < list.nodes.length then
105
10616      for each node in list.nodes do
10717        replace all forward pointers = last with target
108
10918      if node at target has forward[0] != NIL then
11019        forward[0].prev = target
111
11220      if node at target.prev = last then
11321        node.prev = target
114
11522      while list.level > 1 and list.header.forward[list.level - 1] = NIL do
11623        list.level -= 1
117
11824      return removed.value
119```
120
121## Visual Examples
122An initial, empty skip list with one level and no data:
123```text
124S0: HEAD -> None
125```
126
127Inserting the first node triggers an automatic tower level, even if it ends up empty. This provides the algorithm with a starting point:
128```text
129S1: HEAD ----------> None
130S0: HEAD -> [ 5 ] -> None
131```
132
133After inserting `['a', 'c', 'e', 'd', 'b', 'i', 'g', 'h', 'f']`, the list's `SkipNodes` might contain the following towers.
134```text
135HEAD[0]: [1, 2, 9, 7]
136a[1]: [5]
137c[2]: [4, 4]
138e[3]: [9]
139d[4]: [3, 9]
140b[5]: [2]
141i[6]: []
142g[7]: [8, 6, 6]
143h[8]: [6]
144f[9]: [7, 7, 7]
145```
146Note that its always possible to tell the last item in the list because its tower is empty. This makes sense, because the last element within the sorted arrangement can only point to `None`. As you can see by the index notation on the left-hand side of the table, the backing structure retains the insertion order; the backing structure remains unsorted.
147
148The structure simply appends elements to the backing structure, so when printed the list retains its insertion order, not its sorted arrangement. As a result, the towers appear to contain rather nonsensical values. However, if you follow the indexes from the `HEAD` node, and re-arrange the nodes into _lexicographically sorted order_, which is what the navigational algorithms in the skiplist achieve, you get the following towers.
149```text
150HEAD[0]: [1, 2, 9, 7]
151a[1]: [5]
152b[5]: [2]
153c[2]: [4, 4]
154d[4]: [3, 9]
155e[3]: [9]
156f[9]: [7, 7, 7]
157g[7]: [8, 6, 6]
158h[8]: [6]
159i[6]: []
160```
161
162When you rotate the mapping 90 degrees you can start to visualize the skip list layers as logically linked lists formed by "next" element indexes.
163```text
164L3: [ g[7] ] -> None
165L2: [ f[9] ] -> [ g[7] ] -> [ i[6] ] -> None
166L1: [ c[2] ] -> [ d[4] ] -> [ f[9] ] -> [ g[7] ] -> [ i[6] ] -> None
167L0: [ a[1] ] -> [ b[5] ] -> [ c[2] ] -> [ d[4] ] -> [ e[3] ] -> [ f[9] ] -> [ g[7] ] -> [ h[8] ] -> [ i[6] ] -> None
168```
169Finally, if you extend each "next" index reference to align with its sorted position within the list, a classical skip list diagram of towers emerges.
170```text
171L3: HEAD -------------------------------------------------------------------------> [ g[7] ] -------------------------> None
172L2: HEAD -------------------------------------------------------------> [ f[9] ] -> [ g[7] ] -------------> [ i[6] ] -> None
173L1: HEAD -------------------------> [ c[2] ] -> [ d[4] ] -------------> [ f[9] ] -> [ g[7] ] -------------> [ i[6] ] -> None
174L0: HEAD -> [ a[1] ] -> [ b[5] ] -> [ c[2] ] -> [ d[4] ] -> [ e[3] ] -> [ f[9] ] -> [ g[7] ] -> [ h[8] ] -> [ i[6] ] -> None
175```
176
177# Example code
178```rust
179    let mut list = dsa_rust::sequences::indexed_skip_list::SkipList::<char>::new();
180
181    // An unsorted list of values and a sorted version to compare against
182    let values = ['a', 'c', 'e', 'd', 'b', 'i', 'g', 'h', 'f'];
183    let sorted = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
184
185    // Inserts unsorted values into the skip list with a consuming iterator
186    for e in values.into_iter() {
187        list.insert(e)
188    }
189
190    // Illustrates that the list exists as a sorted invariant
191    for (i, e) in list.iter().enumerate() {
192        assert_eq!(e, &sorted[i]);
193    }
194
195    // Illustrates the Kth function in a 0-indexed list.
196    // That is, e occupies the 2 index for insertion order,
197    // but is the 4th element in the 0-indexed sorted arrangement.
198    assert_eq!(list.get_kth(4).unwrap(), &'e');
199
200    // Query by range using Rust's RangeBounds semantics
201    let val = ['c', 'd', 'e', 'f'];
202    for (i, e) in list.range('c'..='f').enumerate() {
203        assert_eq!(e, &val[i])
204    }
205
206```
207*/
208
209use rand::Rng; // For coin flips
210use std::borrow::Borrow; // For passing borrowed parameters
211use std::ops::{Bound, RangeBounds}; // For range iterators
212
213const MAX_HEIGHT: usize = 32;
214//const MAX_HEIGHT: usize = 10;
215
216#[derive(Clone, Debug)]
217struct SkipNode<T> {
218    value: Option<T>,                  // None for sentinel
219    next: [Option<usize>; MAX_HEIGHT], // forward links
220    prev: Option<usize>,               // back links at s0 for reverse iteration
221                                       //height: usize                      // stores the node's "tower" height
222}
223
224pub struct SkipList<T> {
225    nodes: Vec<SkipNode<T>>,
226    height: usize,
227}
228impl<T: Ord> Default for SkipList<T> {
229    fn default() -> Self {
230        Self::new()
231    }
232}
233impl<T: Ord> SkipList<T> {
234    /// Creates a new, empty SkipList.
235    pub fn new() -> Self {
236        let sentinel = SkipNode {
237            value: None,
238            next: [None; MAX_HEIGHT],
239            prev: None,
240        };
241
242        Self {
243            nodes: vec![sentinel],
244            height: 1,
245        }
246    }
247
248    /// Returns the number of elements in the list.
249    pub fn len(&self) -> usize {
250        // Even empty lists have a single HEAD node,
251        // which does not count
252        self.nodes.len() - 1
253    }
254
255    /// Wrapper for `len()` that returns a Boolean
256    /// indicating whether the list is empty.
257    pub fn is_empty(&self) -> bool {
258        self.nodes.len() - 1 == 0
259    }
260
261    /// Returns the a reference to the entry associated with the search key 
262    /// if it exists in the list, otherwise returns `None` to indicate 
263    /// that the key is not in the list. 
264    ///
265    /// Represents Pugh's canonical `Search` operation as described in the
266    /// <a href="https://15721.courses.cs.cmu.edu/spring2018/papers/08-oltpindexes1/pugh-skiplists-cacm1990.pdf" target="_blank" rel="noopener noreferrer">original paper</a>.
267    pub fn get<Q>(&self, key: &Q) -> Option<&T>
268    where
269        Q: Ord + ?Sized,
270        T: Borrow<Q>,
271    {
272        //let idx = self.skip_search(key);
273        let idx = self.find_predecessors(key)[0];
274        let next = self.nodes[idx].next[0]?;
275        let val = self.nodes[next].value.as_ref()?;
276    
277        (val.borrow() == key).then_some(val)
278    }
279    
280    /// Returns a Boolean indicating whether the supplied search key 
281    /// exists in the list.
282    ///
283    /// Wrapper for the public `get()` operation, which itself wraps
284    /// the private `skip_search()` operation.
285    pub fn contains<Q>(&self, key: &Q) -> bool
286    where
287        Q: Ord + ?Sized,
288        T: Borrow<Q>,
289    {
290        self.get(key).is_some()
291    }
292
293    /// Inserts a new entry into the skip list.
294    ///
295    /// Allows duplicates, where ordering is determined by insertion order
296    /// such that the most recent duplicates come before older entries.
297    pub fn insert(&mut self, entry: T) {
298
299        // Insert(list, search_key, newValue)
300        //   local update[1..MaxLevel]
301        //   x = list.header
302        //   for i = list.level downto 1 do
303        //     while x.forward[i].key < search_key do
304        //       x = x.forward[i]
305        //     // x.key < search_key <= x.forward[i].key
306        //     update[i] = x
307
308
309        // Chooses a random tower height and resets the list height
310        // if it is taller than the current list height
311        let height = self.random_height();
312        if height > self.height {
313            self.height = height;
314        }
315
316        // find_predecessors returns an array of predecessor positions
317        // at each level for the splice point where update[0] is the 
318        // entry in the base list strictly < entry
319        let update = self.find_predecessors(&entry);
320        let prev_idx = update[0];
321        let new_index = self.nodes.len(); // Backing list insertion index
322        let next_idx = self.nodes[prev_idx].next[0];
323
324        self.nodes.push(SkipNode {
325            value: Some(entry),
326            next: [None; MAX_HEIGHT],
327            prev: Some(prev_idx),
328        });
329
330        // Reset the previous and current entry's next and previous 
331        // positions, respectively
332        // take() only yields the number of elements in update up to 
333        // the list's height providing a minimal number of loop iterations
334        for (level, _) in update.iter().enumerate().take(height) {
335            let prev_idx = update[level];
336            self.nodes[new_index].next[level] = self.nodes[prev_idx].next[level];
337            self.nodes[prev_idx].next[level] = Some(new_index);
338        }
339
340        // If there is a "next" node it must now point back to the new node
341        if let Some(next_idx) = next_idx {
342            self.nodes[next_idx].prev = Some(new_index);
343        }
344    }
345
346    /// Removes and returns the value for a given key, if it exists in 
347    /// the list. Returns None if the key does not exist in the list. 
348    /// 
349    /// This function does not technically adhere to Pugh's original 
350    /// removal algorithm. It uses [Vec::swap_remove] for simplified 
351    /// backing list compaction with the side effect of re-ordering remaining 
352    /// elements. The resultant removal time is therefore _O(n * height)_, 
353    /// which is _O(n * log(n)) expected_, and _O(n^2)_ worst case.
354    pub fn remove<Q>(&mut self, key: &Q) -> Option<T>
355    where
356        Q: Ord + ?Sized,
357        T: Borrow<Q>,
358    {
359
360        //  Delete(list, search_key)
361        //    local update[1..MaxLevel]
362        //    x = list.header
363        //    for i = list.level downto 1 do
364        //      while x.forward[i].key < search_key do
365        //        x = x.forward[i]
366        //      update[i] = x
367        //    x = x.forward[1]
368        //    if x.key = search_key then
369        //      for i = 1 to list.level do
370        //        if update[i].forward[i] != x then break
371        //        update[i].forward[i] = x.forward[i]
372        //      free(x)
373        //      while list.level > 1 and
374        //        list.header.forward[list.level] == NIL do
375        //        list.level = list.level – 1
376
377        // Pre-fetch precessors for target removal node
378        let mut update = self.find_predecessors(key);
379    
380        // Check if the target is in the list, if it is, return its index
381        let target = match self.nodes[update[0]].next[0] {
382            Some(idx)
383                if self.nodes[idx]
384                    .value
385                    .as_ref()
386                    .is_some_and(|v| v.borrow() == key) =>
387            {
388                idx
389            }
390            _ => return None,
391        };
392    
393        // Find the last node in the backing structure
394        let last_idx = self.nodes.len() - 1;
395    
396        // Remove the prev and next positions from adjacent nodes
397        if let Some(next_idx) = self.nodes[target].next[0] {
398            self.nodes[next_idx].prev = self.nodes[target].prev;
399        }
400        for (level, val) in update.iter_mut().enumerate().take(self.height) {
401            if self.nodes[*val].next[level] == Some(target) {
402                self.nodes[*val].next[level] = self.nodes[target].next[level];
403            }
404        }
405    
406        // Actual node removal
407        let removed_node = self.nodes.swap_remove(target);
408    
409        // Set next/prev positions for the node that just got swapped 
410        // into the hole left by the removal
411        if target < self.nodes.len() {
412            // Fix next positions
413            for node in &mut self.nodes {
414                for next in node.next.iter_mut().take(self.height) {
415                    if *next == Some(last_idx) {
416                        *next = Some(target);
417                    }
418                }
419            }
420
421            // Repair adjacent backward links after relocation
422            if let Some(next_idx) = self.nodes[target].next[0] {
423                self.nodes[next_idx].prev = Some(target);
424            }
425            
426            // Repair relocated predecessor reference
427            if self.nodes[target].prev == Some(last_idx) {
428                self.nodes[target].prev = Some(target);
429            }        
430        }
431
432        // Reduce the list's height, in case the removed tower was tallest
433        while self.height > 1 &&
434            self.nodes[0].next[self.height - 1].is_none()
435        {
436            self.height -= 1;
437        }
438
439        // Return just the entry, not the entire node
440        removed_node.value
441    }
442
443    /// Returns the Kth value in the list, if it exists.
444    pub fn get_kth(&self, k: usize) -> Option<&T> {
445        let mut idx = self.nodes[0].next[0];
446        let mut i = 0;
447        while let Some(current) = idx {
448            if i == k {
449                return self.nodes[current].value.as_ref();
450            }
451            idx = self.nodes[current].next[0];
452            i += 1;
453        }
454        None
455    }
456
457    /// Returns an inclusive iterator over a range of values
458    /// in the list from `start` to `end`.
459    pub fn range<Q, R>(&self, range: R) -> RangeIter<'_, T, Q, R>
460    where
461        Q: Ord + ?Sized,
462        T: Borrow<Q>,
463        R: RangeBounds<Q>,
464    {
465        // FIND FRONT
466        let front = match range.start_bound() {
467            Bound::Included(start) => self.nodes[self.find_predecessors(start)[0]].next[0],
468            Bound::Excluded(start) => {
469                let idx = self.nodes[self.find_predecessors(start)[0]].next[0];
470                if let Some(i) = idx {
471                    if self.nodes[i].value.as_ref().unwrap().borrow() == start {
472                        self.nodes[i].next[0]
473                    } else {
474                        Some(i)
475                    }
476                } else {
477                    None
478                }
479            }
480            Bound::Unbounded => self.nodes[0].next[0],
481        };
482
483        // FIND BACK
484        let back = match range.end_bound() {
485            Bound::Included(end) => {
486                // Find predecessors of 'end'.
487                // If the element at the end of the search IS 'end', that's our back.
488                // If not, the predecessor itself is our back.
489                let update = self.find_predecessors(end);
490                let candidate = self.nodes[update[0]].next[0];
491                if let Some(idx) = candidate {
492                    if self.nodes[idx].value.as_ref().unwrap().borrow() == end {
493                        Some(idx)
494                    } else {
495                        // Predicate check: Ensure we aren't returning the sentinel (idx 0)
496                        if update[0] == 0 {
497                            None
498                        } else {
499                            Some(update[0])
500                        }
501                    }
502                } else if update[0] == 0 {
503                    None
504                } else {
505                    Some(update[0])
506                }
507            }
508            Bound::Excluded(end) => {
509                let update = self.find_predecessors(end);
510                if update[0] == 0 {
511                    None
512                } else {
513                    Some(update[0])
514                }
515            }
516            Bound::Unbounded => {
517                // To find the absolute end, we find predecessors for a
518                // "theoretically infinite" value
519                // or simply walk the tallest tower to the end.
520                let mut curr = 0;
521                for level in (0..self.height).rev() {
522                    while let Some(next_idx) = self.nodes[curr].next[level] {
523                        curr = next_idx;
524                    }
525                }
526                if curr == 0 {
527                    None
528                } else {
529                    Some(curr)
530                }
531            }
532        };
533
534        RangeIter {
535            list: self,
536            front,
537            back,
538            range,
539            _marker: std::marker::PhantomData,
540        }
541    }
542
543    /// Returns an iterator over borrowed values in the list.
544    pub fn iter(&self) -> Iter<'_, T> {
545        // Walk the express lanes to find the very last node in O(log n) time
546        let mut tail = 0;
547        for level in (0..self.height).rev() {
548            while let Some(next_idx) = self.nodes[tail].next[level] {
549                tail = next_idx;
550            }
551        }
552
553        Iter {
554            list: self,
555            next: self.nodes[0].next[0], // First node after sentinel
556            prev: if tail == 0 { None } else { Some(tail) },
557        }
558    }
559
560    // Utility functions
561    ////////////////////
562
563    // Uses the external crate rand to determine the height h
564    // of a given tower which is always 1 <= h < MAX_HEIGHT
565    // by performing a series of "coin flips".
566    fn random_height(&self) -> usize {
567        let mut level = 1;
568        let mut rng = rand::rng();
569        while level < MAX_HEIGHT && rng.random::<bool>() {
570            level += 1;
571        }
572        level
573    }
574
575    // Represents the heart of the skip list. This function is used
576    // by the `insert()`, `remove()`, `range()`, `locate()` (and by
577    // proxy `contains()`) functions.
578    //
579    // Returns an array of integers representing entries for each level 
580    // in the list that are strictly less than the search key at each 
581    // level, where the 0th index represents the base list.
582    //
583    // Performs dual duty in regards to Pugh's original design.
584    // Useful as a basic skip_search by capturing the base list position
585    // of the entry strictly < search_key as the 0th array index in the 
586    // return, as well as providing a list of previous positions at the 
587    // splice/split point for insert and delete operations.
588    fn find_predecessors<Q>(&self, key: &Q) -> [usize; MAX_HEIGHT]
589    where
590        Q: Ord + ?Sized,
591        T: Borrow<Q>,
592    {
593        let mut update = [0usize; MAX_HEIGHT];
594        let mut idx = 0;
595
596        for level in (0..self.height).rev() {
597            loop {
598                match self.nodes[idx].next[level] {
599                    None => break,
600                    Some(next_idx) => {
601                        let next_val = self.nodes[next_idx].value.as_ref().unwrap();
602                        if next_val.borrow() >= key {
603                            break;
604                        }
605                        idx = next_idx;
606                    }
607                }
608            }
609            // Record the node index in the update list before descending
610            update[level] = idx; 
611        }
612        update
613    }
614
615    /// Represents the heart of the skip list. This function is used
616    /// by the `get()`, `insert()`, `remove()`, `range()`, and 
617    /// `contains()`) functions.
618    ///
619    /// Returns the index of the largest entry that is 
620    /// strictly less than the provided key.
621    ///
622    /// NOTE: UNUSED
623    fn _skip_search<Q>(&self, key: &Q) -> usize
624    where
625        Q: Ord + ?Sized,
626        T: Borrow<Q>,
627    {
628        // Empty lists have a single sentinel node
629        if self.nodes.len() == 1 { return 0 };
630
631        // p = s: Always start at the HEAD node (index 0)
632        let mut pos = 0usize;
633
634        // Iterate through levels from top to bottom (the vertical "below(p)" steps)
635        for level in (0..self.height).rev() {
636            // "Scan forward" horizontally across the current level
637            while self.nodes[pos].next[level].is_some() {
638                // Peek at the NEXT node index on the current logical linked list
639                match self.nodes[pos].next[level] {
640                    // Get the next node's value safely.
641                    // If the search key is >= the forward node's value,
642                    // advance the pos to that node. If the next node is
643                    // either > key or None, break the loop, which
644                    // moves to the next level.
645                    Some(next_idx) => {
646                        let next_val = self.nodes[next_idx].value.as_ref().unwrap().borrow();
647                        if next_val < key {
648                            pos = next_idx;
649                        } else {
650                            break; // Break and descend a level
651                        }
652                    }
653                    None => {
654                        break; // Break and descend a level
655                    }
656                }
657            }
658        }
659
660        // If the position never advances beyond the sentinel, 
661        // the key is not either doesn't exist in the list, 
662        // or it belongs as the first element
663        pos
664    }
665
666    /// Returns the traversal path of a search key by
667    /// re-using the skip_search logic. The only difference is that
668    /// this traversal records each index and returns the path.
669    fn _traversal<Q>(&self, key: &Q) -> Vec<T>
670    where
671        Q: Ord + ?Sized,
672        T: Borrow<Q> + Clone,
673    {
674        let mut vec = Vec::new();
675
676        // p = s: Always start at the HEAD node (index 0)
677        let mut pos = 0usize;
678
679        // Iterate through levels from top to bottom (the vertical "below(p)" steps)
680        for level in (0..self.height).rev() {
681            // "Scan forward" horizontally across the current level
682            while self.nodes[pos].next[level].is_some() {
683                // Peek at the NEXT node index on the current logical linked list
684                match self.nodes[pos].next[level] {
685                    // Get the next node's value safely.
686                    // If the search key is >= the forward node's value,
687                    // advance the pos to that node. If the next node is
688                    // either > key or None, break the loop, which
689                    // moves to the next level.
690                    Some(next_idx) => {
691                        let next_val = self.nodes[next_idx].value.as_ref().unwrap().borrow();
692                        if next_val < key {
693                            vec.push(self.nodes[next_idx].value.clone().unwrap());
694                            pos = next_idx;
695                        } else {
696                            break; // Break and descend a level
697                        }
698                    }
699                    None => {
700                        break; // Break and descend a level
701                    }
702                }
703            }
704        }
705        vec
706    }
707}
708
709pub struct Iter<'a, T> {
710    list: &'a SkipList<T>,
711    next: Option<usize>,
712    prev: Option<usize>,
713}
714impl<'a, T> Iterator for Iter<'a, T> {
715    type Item = &'a T;
716
717    fn next(&mut self) -> Option<Self::Item> {
718        let idx = self.next?;
719        let value = self.list.nodes[idx].value.as_ref()?;
720
721        if self.next == self.prev {
722            self.next = None;
723            self.prev = None;
724        } else {
725            self.next = self.list.nodes[idx].next[0];
726        }
727        Some(value)
728    }
729}
730impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
731    fn next_back(&mut self) -> Option<Self::Item> {
732        let idx = self.prev?;
733        let value = self.list.nodes[idx].value.as_ref()?;
734
735        if self.prev == self.next {
736            self.next = None;
737            self.prev = None;
738        } else {
739            let prev = self.list.nodes[idx].prev;
740            // Sentinel check: don't yield index 0
741            self.prev = if prev == Some(0) { None } else { prev };
742        }
743        Some(value)
744    }
745}
746
747pub struct RangeIter<'a, T, Q, R>
748where
749    Q: ?Sized,
750    R: RangeBounds<Q>,
751{
752    list: &'a SkipList<T>,
753    front: Option<usize>, // Moves forward
754    back: Option<usize>,  // Moves backward
755    range: R,
756    _marker: std::marker::PhantomData<Q>,
757}
758impl<'a, T, Q, R> Iterator for RangeIter<'a, T, Q, R>
759where
760    Q: Ord + ?Sized,
761    T: Borrow<Q>,
762    R: RangeBounds<Q>,
763{
764    type Item = &'a T;
765
766    fn next(&mut self) -> Option<Self::Item> {
767        let idx = self.front?;
768
769        // Boundary Check
770        let value = self.list.nodes[idx].value.as_ref().unwrap();
771        if !self.range.contains(value.borrow()) {
772            self.front = None;
773            return None;
774        }
775
776        // Meet/Cross Check: If front matches back, this is the last element
777        if self.front == self.back {
778            self.front = None;
779            self.back = None;
780        } else {
781            self.front = self.list.nodes[idx].next[0];
782        }
783
784        Some(value)
785    }
786}
787impl<'a, T, Q, R> DoubleEndedIterator for RangeIter<'a, T, Q, R>
788where
789    Q: Ord + ?Sized,
790    T: Borrow<Q>,
791    R: RangeBounds<Q>,
792{
793    fn next_back(&mut self) -> Option<Self::Item> {
794        let idx = self.back?;
795
796        // Boundary Check
797        let value = self.list.nodes[idx].value.as_ref().unwrap();
798        if !self.range.contains(value.borrow()) {
799            self.back = None;
800            return None;
801        }
802
803        // Meet/Cross Check
804        if self.back == self.front {
805            self.back = None;
806            self.front = None;
807        } else {
808            // Move back, but ensure we don't land on the sentinel (idx 0)
809            let prev = self.list.nodes[idx].prev;
810            self.back = if prev == Some(0) { None } else { prev };
811        }
812
813        Some(value)
814    }
815}
816
817impl<'a, T: Ord> IntoIterator for &'a SkipList<T> {
818    type Item = &'a T;
819    type IntoIter = Iter<'a, T>;
820
821    fn into_iter(self) -> Self::IntoIter {
822        self.iter()
823    }
824}
825
826#[test]
827fn one() {
828    let mut list = SkipList::<char>::new();
829
830    // Tests basic housekeeping on empty list
831    assert_eq!(list.len(), 0);
832    assert!(list.is_empty());
833    assert!(!list.contains(&'z'));
834
835    // Inserts 9 values into the skip list
836    // with a consuming iterator, moving values
837    // into the list
838    let values = ['a', 'c', 'e', 'd', 'b', 'i', 'g', 'h', 'f'];
839    println!("Insert elements in order: {:?}", &values);
840    for e in values.into_iter() {
841        list.insert(e)
842    }
843    println!("LIST DIAGNOSTICS: \n\theight: {}\n\tlength: {}", list.height, list.nodes.len());
844    println!("Tower contents by insertion order, NOT sorted order:");
845    for (i, e) in list.nodes.iter().enumerate() {
846        // Collect only the Some values into a new Vec
847        //let values: Vec<_> = e.next.iter().filter_map(|&x| x).collect();
848        let values: Vec<_> = e.next.iter().collect();
849        match e.value {
850            Some(val) => println!("{val:>04} [{i}]: {values:?}"),
851            None => println!("HEAD [{i}]: {values:?}"),
852        }
853        //if let Some(val) = e.value {
854        //    let v = &val.to_string();
855        //    println!("{v}[{i}]: {values:?}");
856        //} else {
857        //    println!("HEAD[0]: {values:?}");
858        //}
859    }
860    println!();
861
862    // Tests that len gets updated properly
863    assert_eq!(list.len(), 9);
864    assert!(list.contains(&'g'));
865
866    // Tests basic ordering and iteration
867    // Basic iteration with iter()
868    // Clippy wants enumerate instead of external loop counter
869    let sorted = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'];
870    for (i, e) in list.iter().enumerate() {
871        assert_eq!(e, &sorted[i]);
872    }
873    // Double-ended iteration with rev()
874    // Clippy wants saturating_sub instead of loop counter
875    let mut i = 8;
876    for e in list.iter().rev() {
877        assert_eq!(e, &sorted[i]);
878        if i > 0 {
879            i = i.saturating_sub(1)
880        };
881    }
882    // Or if you wanna be fancy about it
883    // zip() stops as soon as one iterator ends,
884    // eliminating the need for an overflow check
885    for (e, i) in list.iter().rev().zip((0..=8).rev()) {
886        assert_eq!(e, &sorted[i]);
887    }
888
889    // Iterator inferance using the IntoIter impl
890    let mut i = 0;
891    #[allow(clippy::explicit_counter_loop)]
892    for e in &list {
893        assert_eq!(e, &sorted[i]);
894        i += 1;
895    }
896
897    // Tests the Kth function in a 0-indexed list
898    assert_eq!(list.get_kth(6).unwrap(), &'g');
899
900    // Tests the range function
901    // NOTE: char is Copy so you dont strictly need to borrow
902    // when setting range bounds, these tests illustrate both
903    // borrowing and not; Note that each bounds must match
904    // so no (&'a'..'f'), only ('a'..'f') or (&'a'..&'f')
905    // Midlist (exclusive)
906    let val = ['c', 'd', 'e'];
907    //for (i, e) in list.range(&'c', &'f').enumerate() {
908    for (i, e) in list.range('c'..'f').enumerate() {
909        assert_eq!(e, &val[i])
910    }
911    // Midlist (inclusive)
912    let val = ['c', 'd', 'e', 'f'];
913    //for (i, e) in list.range(&'c', &'f').enumerate() {
914    for (i, e) in list.range('c'..='f').enumerate() {
915        assert_eq!(e, &val[i])
916    }
917    // Start of list
918    let val = ['a', 'b', 'c', 'd', 'e', 'f'];
919    //for (i, e) in list.range(&'a', &'f').enumerate() {
920    for (i, e) in list.range(..&'f').enumerate() {
921        assert_eq!(e, &val[i])
922    }
923    // End of list
924    let val = ['e', 'f', 'g', 'h', 'i'];
925    for (i, e) in list.range(&'e'..).enumerate() {
926        assert_eq!(e, &val[i])
927    }
928
929    // Tests remove(e)
930    // Removes the first element
931    println!("Remove 'a'");
932    list.remove(&'a');
933    // Removes an arbitrary element
934    println!("Remove 'e'");
935    list.remove(&'e');
936    // Removes the last element
937    println!("Remove 'i'");
938    list.remove(&'i');
939    // List shrinks as expected
940    assert_eq!(list.len(), 6);
941    // List no longer contains elements
942    assert!(!list.contains(&'e'));
943    assert!(!list.contains(&'a'));
944    // Cant remove what isn't there!
945    assert!(list.remove(&'z').is_none());
946    // Debug prints new layout
947    print!("List updated values: [");
948    for e in list.iter() {
949        print!("{e:#?} ")
950    }
951    println!("]");
952
953    // Debug prints the tower contents
954    println!("LIST DIAGNOSTICS: \n\theight: {}\n\tlength: {}", list.height, list.nodes.len());
955    println!("Tower contents by insertion order, NOT sorted order:");
956    for (i, e) in list.nodes.iter().enumerate() {
957        // Collect only the Some values into a new Vec
958        //let values: Vec<_> = e.next.iter().filter_map(|&x| x).collect();
959        let values: Vec<_> = e.next.iter().collect();
960        match e.value {
961            Some(val) => println!("{val:>04} [{i}]: {values:?}"),
962            None => println!("HEAD [{i}]: {values:?}"),
963        }
964    }
965    println!();
966
967    // Tests skip_search(e), find_predecessors(e) and their dependencies:
968    // contains(e), get(e), and find_val(e)
969    //
970    // An element in the list
971    let node = 'h';
972    assert_eq!(list._skip_search(&node), 6); // 6 is g which is < h
973    assert_eq!(list.find_predecessors(&node)[0], 6); // 6 is g which is < h
974    assert!(list.contains(&node));
975    assert_eq!(list.get(&node).unwrap(), &'h');
976    // An element at the beginning of the list
977    let node = 'b';
978    assert_eq!(list._skip_search(&node), 0); 
979    assert_eq!(list.find_predecessors(&node)[0], 0); 
980    assert!(list.contains(&node));
981    assert_eq!(list.get(&node).unwrap(), &'b');
982    // An element not in the list
983    // 'j' is not in the list, but skip_search returns 6 because
984    // thats the position that 'i' lives at due to insertion order,
985    // and 'i' < 'j'
986    let node = 'j';
987    assert_eq!(list._skip_search(&node), 3); // 3 is h, the last entry
988    assert_eq!(list.find_predecessors(&node)[0], 3); // 3 is h, the last entry
989    assert!(!list.contains(&node));
990    assert!(list.get(&node).is_none());
991    // An element that was previously in the list, but removed
992    let node = 'a';
993    assert_eq!(list._skip_search(&node), 0); // belongs after HEAD
994    assert_eq!(list.find_predecessors(&node)[0], 0); // belongs after HEAD
995    assert!(!list.contains(&node));
996    assert!(list.get(&node).is_none());
997
998    // A bunch of random list mutations to ensure coherence
999    list.insert('p');
1000    list.insert('u');
1001    list.insert('w');
1002    list.remove(&'p');
1003    list.insert('l');
1004    list.insert('m');
1005    list.remove(&'f');
1006    list.remove(&'o');
1007    list.insert('q');
1008    list.remove(&'m');
1009    list.insert('x');
1010    list.insert('z');
1011
1012    // Visual component:
1013    // Combines contains(e) and prints traversal() as proof
1014    let trav = list._traversal(&'g');
1015    let con = list.contains(&'g');
1016    println!("Contains 'g': {con:?}");
1017    println!("Traversal: {trav:?}");
1018    let trav = list._traversal(&'j');
1019    let con = list.contains(&'j');
1020    println!("Contains 'j': {con:?}");
1021    println!("Traversal: {trav:?}");
1022    let trav = list._traversal(&'a');
1023    let con = list.contains(&'a');
1024    println!("Contains 'a': {con:?}");
1025    println!("Traversal: {trav:?}");
1026
1027    // Tests traversal ordering
1028    let l2 = ['b', 'c', 'd', 'g', 'h', 'l', 'q', 'u', 'w', 'x', 'z'];
1029    for (val, i) in list.iter().zip(0..=5) {
1030        assert_eq!(val, &l2[i]);
1031    }
1032    // Visual confirmation of correct traversal
1033    print!("List values:\n   ");
1034    for e in list.iter() {
1035        print!("{e:#?} ")
1036    }
1037    println!();
1038
1039    //panic!();
1040}
1041
1042#[test]
1043// AI-written "stress" test
1044fn test_skip_list_removal_integrity() {
1045    // Assumes your SkipList has a standard New or Default implementation
1046    let mut list = SkipList::new();
1047    
1048    // 1. Insert a sequence of numbers.
1049    // This allows your natural random_height() generator to build up 
1050    // a multi-level tower structure organically.
1051    let total_elements = 300;
1052    for i in 0..total_elements {
1053        list.insert(i);
1054    }
1055
1056    // 2. Remove elements from the middle of the list.
1057    // This forces swap_remove to repeatedly pull the last element of the Vec
1058    // into the newly created holes, triggering your global repair loops.
1059    for i in (50..200).step_by(2) {
1060        list.remove(&i);
1061    }
1062
1063    // 3. STRUCTURAL AUDIT
1064    // Scan every single surviving node's next pointers across every level.
1065    // If swap_remove left a stale index behind, it will point out-of-bounds.
1066    let current_len = list.nodes.len();
1067    for idx in 0..current_len {
1068        for level in 0..list.height {
1069            if let Some(next_idx) = list.nodes[idx].next[level] {
1070                
1071                // Assert 1: Out-of-bounds index protection
1072                assert!(
1073                    next_idx < current_len,
1074                    "CORRUPTION: Node at index {idx} on level {level} points to index {next_idx}, \
1075                     which is out-of-bounds for a Vec of length {current_len}!"
1076                );
1077
1078                // Assert 2: Level 0 backlink symmetric validation
1079                if level == 0 {
1080                    assert_eq!(
1081                        list.nodes[next_idx].prev,
1082                        Some(idx),
1083                        "CORRUPTION: Link symmetry broken! Node {} points forward to {}, \
1084                         but {} points backward to {:?}",
1085                        idx, next_idx, next_idx, list.nodes[next_idx].prev
1086                    );
1087                }
1088            }
1089        }
1090    }
1091
1092    // 4. ALGORITHMIC AUDIT
1093    // Verify that every single element that wasn't deleted is still perfectly 
1094    // searchable via skip_search. If a lane broke, skip_search will overshoot 
1095    // or fail to track the element.
1096    for i in 0..total_elements {
1097        // Skip the elements we explicitly deleted
1098        if (50..200).contains(&i) && i % 2 == 0 {
1099            continue;
1100        }
1101
1102        // Your skip_search returns a valid usize position
1103        let pos = list.find_predecessors(&i)[0];
1104        
1105        // Ensure the pos returned actually matches our search target 
1106        // or points to its direct predecessor.
1107        if pos == 0 {
1108            // If it returned the sentinel, the first item in the list must be >= i
1109            if let Some(first_idx) = list.nodes[0].next[0] {
1110                let first_val = list.nodes[first_idx].value.as_ref().unwrap();
1111                assert!(first_val >= &i);
1112            }
1113        } else {
1114            let found_val = list.nodes[pos].value.as_ref().unwrap();
1115            assert!(found_val <= &i, "skip_search returned a node greater than the key!");
1116        }
1117    }
1118
1119    println!("LIST DIAGNOSTICS: \n\theight: {}\n\tlength: {}", list.height, list.nodes.len());
1120    println!("Tower contents by insertion order, NOT sorted order:");
1121    for (i, e) in list.nodes.iter().enumerate() {
1122        // Collect only the Some values into a new Vec
1123        //let values: Vec<_> = e.next.iter().filter_map(|&x| x).collect();
1124        let values: Vec<_> = e.next.iter().collect();
1125        match e.value {
1126            Some(val) => println!("{val:>04} [{i}]: {values:?}"),
1127            None => println!("HEAD [{i}]: {values:?}"),
1128        }
1129    }
1130    println!();
1131    //panic!()
1132}