From e9550db4b393a0b59679c8d07797c61fc6df3678 Mon Sep 17 00:00:00 2001 From: Ed Guloien Date: Mon, 1 Jun 2026 15:49:39 -0400 Subject: [PATCH] added simple linked list --- .gitignore | 1 + Cargo.lock | 7 ++++ Cargo.toml | 6 ++++ src/main.rs | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..90adf41 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "linked-list" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..389c3d3 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "linked-list" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..92bb279 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,102 @@ + +struct List { head: Option>, len: usize } +struct Node { + value: u32, + next: Option> +} + +impl List { + pub fn new() -> Self { + List { head: None, len: 0} + } + + pub fn append(&mut self, val: u32) { + let slot = self.walk(self.len); + *slot = Some(Box::new(Node{value: val, next: None})); + self.len += 1; + } + + pub fn insert(&mut self, val: u32, index: usize) { + let slot = self.walk(index); + let rest = slot.take(); + *slot = Some(Box::new(Node { value: val, next: rest })); + self.len += 1; + } + + pub fn remove(&mut self, index: usize) -> Option { + if index >= self.len { + return None; + } + let slot = self.walk(index); + let removed = slot.take()?; + *slot = removed.next; + self.len -= 1; + Some(removed.value) + } + + // walk returns the entry at index + fn walk(&mut self, index: usize) -> &mut Option> { + let mut iter = &mut self.head; + for _ in 0..index { + match iter { + Some(node) => iter = &mut node.next, + None => break, + } + } + iter + } + + pub fn as_vec(&self) -> Vec { + let mut result = Vec::new(); + let mut i = &self.head; + while let Some(node) = i { + result.push(node.value); + i = &node.next; + } + result + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } +} + +fn main() { + println!("use cargo test"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_list() { + let mut l = List::new(); + l.append(1); + l.append(2); + l.append(3); + l.append(4); + assert_eq!(l.as_vec(), vec![1,2,3,4]); + + l.remove(2); + assert_eq!(l.as_vec(), vec![1,2,4]); + l.remove(2); + assert_eq!(l.as_vec(), vec![1,2]); + l.remove(2); // too far, no removal + assert_eq!(l.as_vec(), vec![1,2]); + + l.insert(5, 1); + assert_eq!(l.as_vec(), vec![1,5,2]); + l.insert(6, 3); + assert_eq!(l.as_vec(), vec![1,5,2,6]); + + l.remove(0); + assert_eq!(l.as_vec(), vec![5,2,6]); + l.remove(0); + assert_eq!(l.as_vec(), vec![2,6]); + l.remove(0); + assert_eq!(l.as_vec(), vec![6]); + l.remove(0); + assert!(l.is_empty()); + } +}