You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

159 lines
4.3 KiB

# 链表
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)
```rust
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());
}
}
```