链表
A linked list is also a linear
data structure, and each element in the linked list is actually a separate object while all the objects are linked together by the reference filed
in each element. In a doubly linked list
, each node contains, besides the next
node link, a second link field pointing to the previous
node in the sequence. The two links may be called next
and prev
. And many modern operating systems use doubly linked lists to maintain references to active processes, threads and other dynamic objects.
Properties
- Indexing O(n)
- Insertion O(1)
- Beginning O(1)
- Middle (Indexing time+O(1))
- End O(n)
- Deletion O(1)
- Beginning O(1)
- Middle (Indexing time+O(1))
- End O(n)
- Search O(n)
#![allow(unused)] fn main() { use std::fmt::{self, Display, Formatter}; use std::ptr::NonNull; struct Node<T> { val: T, next: Option<NonNull<Node<T>>>, prev: Option<NonNull<Node<T>>>, } impl<T> Node<T> { fn new(t: T) -> Node<T> { Node { val: t, prev: None, next: None, } } } pub struct LinkedList<T> { length: u32, start: Option<NonNull<Node<T>>>, end: Option<NonNull<Node<T>>>, } impl<T> Default for LinkedList<T> { fn default() -> Self { Self::new() } } impl<T> LinkedList<T> { pub fn new() -> Self { Self { length: 0, start: None, end: None, } } pub fn add(&mut self, obj: T) { let mut node = Box::new(Node::new(obj)); // Since we are adding node at the end, next will always be None node.next = None; node.prev = self.end; // Get a pointer to node let node_ptr = Some(unsafe { NonNull::new_unchecked(Box::into_raw(node)) }); match self.end { // This is the case of empty list None => self.start = node_ptr, Some(end_ptr) => unsafe { (*end_ptr.as_ptr()).next = node_ptr }, } self.end = node_ptr; self.length += 1; } pub fn get(&mut self, index: i32) -> Option<&T> { self.get_ith_node(self.start, index) } fn get_ith_node(&mut self, node: Option<NonNull<Node<T>>>, index: i32) -> Option<&T> { match node { None => None, Some(next_ptr) => match index { 0 => Some(unsafe { &(*next_ptr.as_ptr()).val }), _ => self.get_ith_node(unsafe { (*next_ptr.as_ptr()).next }, index - 1), }, } } } impl<T> Display for LinkedList<T> where T: Display, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.start { Some(node) => write!(f, "{}", unsafe { node.as_ref() }), None => Ok(()), } } } impl<T> Display for Node<T> where T: Display, { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.next { Some(node) => write!(f, "{}, {}", self.val, unsafe { node.as_ref() }), None => write!(f, "{}", self.val), } } } #[cfg(test)] mod tests { use super::LinkedList; #[test] fn create_numeric_list() { let mut list = LinkedList::<i32>::new(); list.add(1); list.add(2); list.add(3); println!("Linked List is {}", list); assert_eq!(3, list.length); } #[test] fn create_string_list() { let mut list_str = LinkedList::<String>::new(); list_str.add("A".to_string()); list_str.add("B".to_string()); list_str.add("C".to_string()); println!("Linked List is {}", list_str); assert_eq!(3, list_str.length); } #[test] fn get_by_index_in_numeric_list() { let mut list = LinkedList::<i32>::new(); list.add(1); list.add(2); println!("Linked List is {}", list); let retrived_item = list.get(1); assert!(retrived_item.is_some()); assert_eq!(2 as i32, *retrived_item.unwrap()); } #[test] fn get_by_index_in_string_list() { let mut list_str = LinkedList::<String>::new(); list_str.add("A".to_string()); list_str.add("B".to_string()); println!("Linked List is {}", list_str); let retrived_item = list_str.get(1); assert!(retrived_item.is_some()); assert_eq!("B", *retrived_item.unwrap()); } } }