From 26bad7502fef611b5e23edc20f7418687c570b9d Mon Sep 17 00:00:00 2001 From: Berack96 Date: Tue, 30 Apr 2024 19:13:34 +0200 Subject: [PATCH] Es 07 Lists - with T generic --- src/es07_list_generic.rs | 220 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 - tests/es07_list_generic.rs | 187 +++++++++++++++++++++++++++++++ 3 files changed, 407 insertions(+), 2 deletions(-) create mode 100644 src/es07_list_generic.rs create mode 100644 tests/es07_list_generic.rs diff --git a/src/es07_list_generic.rs b/src/es07_list_generic.rs new file mode 100644 index 0000000..dcadd37 --- /dev/null +++ b/src/es07_list_generic.rs @@ -0,0 +1,220 @@ +#![allow(unused)] + +/** + * Fare una implementazione delle liste doppiamenti linkate come la precedente, ma i metodo get + * rimuove l’elemento nella posizione n e lo ritorna. Per questa implementazione il tipo generico + * T non deve implementare Copy. + +#[derive(Default)] +struct Node { + item: T, + next: Pointer, + prev: Pointer, +} +impl Node { + fn new(item: T) -> Self +} + +type Pointer = Option>>>; + +#[derive(Default)] +pub struct DoublyPointedList { + head: Pointer, + tail: Pointer, + size: usize, +} +impl DoublyPointedList { + pub fn new() -> Self + pub fn is_empty(&self) -> bool + pub fn len(&self) -> usize + pub fn push_back(&mut self, item: T) + pub fn push_front(&mut self, item: T) + pub fn pop_back(&mut self) -> Option + pub fn pop_front(&mut self) -> Option + // Se n e' positivo ritornate l'ennesimo elemento dall'inizio + //della lista mentre se e' negativo lo ritornate dalla coda + //(-1 e' il primo elemento dalla coda) + pub fn get(& self, n:i32) -> Option +} +*/ +use std::{ + borrow::Borrow, + cell::{RefCell, RefMut}, + mem, + rc::Rc, +}; + +type Pointer = Option>>; + +#[derive(Debug)] +pub struct LinkedList { + size: usize, + head: Pointer>, + tail: Pointer>, +} + +#[derive(Debug)] +struct Node { + element: Option, + next: Pointer>, + prev: Pointer>, +} + +impl Node { + pub fn new(element: T) -> Self { + Self { + element: Some(element), + next: None, + prev: None, + } + } + pub fn get(node: &Rc>>) -> RefMut> { + node.as_ref().borrow_mut() + } + pub fn as_memref(self) -> Rc>> { + Rc::new(RefCell::new(self)) + } +} + +impl LinkedList { + pub fn new() -> Self { + Self { + size: 0, + head: None, + tail: None, + } + } + + pub fn is_empty(&self) -> bool { + self.size == 0 + } + + pub fn len(&self) -> usize { + self.size + } + + pub fn push_front(&mut self, element: T) { + let element = Node::new(element).as_memref(); + if let Some(head) = self.head.as_ref() { + Node::get(head).prev = Some(element.clone()); + Node::get(&element).next = Some(head.clone()); + } + if let None = self.tail.as_ref() { + self.tail = Some(element.clone()); + } + + self.head = Some(element.clone()); + self.size += 1; + } + pub fn push_back(&mut self, element: T) { + let element = Node::new(element).as_memref(); + if let Some(tail) = self.tail.as_ref() { + Node::get(tail).next = Some(element.clone()); + Node::get(&element).prev = Some(tail.clone()); + } + if let None = self.tail.as_ref() { + self.head = Some(element.clone()); + } + + self.tail = Some(element.clone()); + self.size += 1; + } + + pub fn pop_front(&mut self) -> Option { + self.pop(true) + } + pub fn pop_back(&mut self) -> Option { + self.pop(false) + } + fn pop(&mut self, from_head: bool) -> Option { + let ptr = if from_head { + &mut self.head + } else { + &mut self.tail + }; + + if let Some(node) = ptr.clone() { + let mut node = Node::get(&node); + + let other = if from_head { + node.next.clone() + } else { + node.prev.clone() + }; + + if let Some(node) = other.clone() { + *ptr = other; + if from_head { + Node::get(&node).prev = None; + } else { + Node::get(&node).next = None; + } + } else { + self.head = None; + self.tail = None; + } + + self.size -= 1; + return mem::take(&mut node.element); + } + None + } + + + pub fn get(&mut self, n: i32) -> Option { + if self.size == 0 { + return None; + } + + let index = n + if n < 0 { self.size as i32 } else { 0 }; + if index == 0 { + self.pop_front() + } else if (index - 1) as usize == self.size { + self.pop_back() + } else if let Some(node) = self.find(index) { + let mut node = Node::get(&node); + let prev = node.prev.clone(); + let next = node.next.clone(); + + match &prev { + Some(val) => Node::get(val).next = next.clone(), + None => self.head = next.clone(), + } + match &next { + Some(val) => Node::get(val).prev = prev.clone(), + None => self.tail = prev.clone(), + } + + self.size -= 1; + mem::take(&mut node.element) + } else { + None + } + } + + fn find(&self, index: i32) -> Pointer> { + if index < 0 || index as usize >= self.size { + return None; + } + + let index = index as usize; + let delta_back = (self.size - index) - 1_usize; + let from_head = index <= delta_back; + + let node = if from_head { &self.head } else { &self.tail }; + let index = if from_head { index } else { delta_back }; + Self::find_node(node, index, from_head) + } + fn find_node(node: &Pointer>, index: usize, from_head: bool) -> Pointer> { + if let Some(node) = node { + return if index == 0 { + Some(node.clone()) + } else { + let node = node.as_ref().borrow(); + let node = if from_head { &node.next } else { &node.prev }; + Self::find_node(node, index - 1, from_head) + }; + } + None + } +} diff --git a/src/lib.rs b/src/lib.rs index 5550ca2..a49103f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,4 @@ pub mod es04_rational_traits; pub mod es05_bank; pub mod es06_list; pub mod es07_list_generic; -pub mod es08_folds; -pub mod es09_auction; diff --git a/tests/es07_list_generic.rs b/tests/es07_list_generic.rs new file mode 100644 index 0000000..1e3c6d8 --- /dev/null +++ b/tests/es07_list_generic.rs @@ -0,0 +1,187 @@ +use esercizi::es07_list_generic::LinkedList; + +#[test] +fn test_front() { + let mut list = LinkedList::new(); + + assert_eq!(0, list.len()); + assert_eq!(true, list.is_empty()); + assert_eq!(None, list.pop_front()); + assert_eq!(true, list.is_empty()); + assert_eq!(0, list.len()); + + list.push_front(50); + assert_eq!(1, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(50), list.pop_front()); + assert_eq!(true, list.is_empty()); + assert_eq!(0, list.len()); + assert_eq!(None, list.pop_front()); + + list.push_front(50); + list.push_front(20); + assert_eq!(2, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(20), list.pop_front()); + assert_eq!(Some(50), list.pop_front()); + assert_eq!(None, list.pop_front()); + + list.push_front(50); + list.push_front(20); + list.push_front(150); + assert_eq!(3, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(150), list.pop_front()); + assert_eq!(Some(20), list.pop_front()); + assert_eq!(Some(50), list.pop_front()); + assert_eq!(None, list.pop_front()); +} + +#[test] +fn test_back() { + let mut list = LinkedList::new(); + + assert_eq!(0, list.len()); + assert_eq!(true, list.is_empty()); + assert_eq!(None, list.pop_back()); + assert_eq!(true, list.is_empty()); + assert_eq!(0, list.len()); + + list.push_back(50); + assert_eq!(1, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(50), list.pop_back()); + assert_eq!(true, list.is_empty()); + assert_eq!(0, list.len()); + assert_eq!(None, list.pop_back()); + + list.push_back(50); + list.push_back(20); + assert_eq!(2, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(20), list.pop_back()); + assert_eq!(Some(50), list.pop_back()); + assert_eq!(None, list.pop_back()); + + list.push_back(50); + list.push_back(20); + list.push_back(150); + assert_eq!(3, list.len()); + assert_eq!(false, list.is_empty()); + assert_eq!(Some(150), list.pop_back()); + assert_eq!(Some(20), list.pop_back()); + assert_eq!(Some(50), list.pop_back()); + assert_eq!(None, list.pop_back()); +} + +#[test] +fn test_mixed() { + let mut list: LinkedList = LinkedList::new(); + assert_eq!(0, list.len()); + + list.push_back(50); + assert_eq!(1, list.len()); + + list.push_front(20); + assert_eq!(2, list.len()); + + list.push_front(10); + assert_eq!(3, list.len()); + + list.push_back(150); + list.push_back(15); + list.push_front(0); + assert_eq!(6, list.len()); + + assert_eq!(Some(15), list.pop_back()); + assert_eq!(5, list.len()); + assert_eq!(Some(0), list.pop_front()); + assert_eq!(4, list.len()); + assert_eq!(Some(150), list.pop_back()); + assert_eq!(3, list.len()); + assert_eq!(Some(50), list.pop_back()); + assert_eq!(2, list.len()); + assert_eq!(Some(10), list.pop_front()); + assert_eq!(1, list.len()); + assert_eq!(Some(20), list.pop_front()); + assert_eq!(0, list.len()); + + assert_eq!(None, list.pop_back()); + assert_eq!(None, list.pop_front()); + + // creo lista [50, 20, 10, 30, 40] + list.push_back(10); + list.push_front(20); + list.push_back(30); + list.push_back(40); + list.push_front(50); + + assert_eq!(Some(50), list.pop_front()); + assert_eq!(Some(20), list.pop_front()); + assert_eq!(Some(10), list.pop_front()); + assert_eq!(Some(30), list.pop_front()); + assert_eq!(Some(40), list.pop_front()); + assert_eq!(None, list.pop_front()); + + list.push_back(10); + list.push_front(20); + list.push_back(30); + list.push_back(40); + list.push_front(50); + + assert_eq!(Some(40), list.pop_back()); + assert_eq!(Some(30), list.pop_back()); + assert_eq!(Some(10), list.pop_back()); + assert_eq!(Some(20), list.pop_back()); + assert_eq!(Some(50), list.pop_back()); + assert_eq!(None, list.pop_back()); +} + +#[test] +fn test_get() { + let mut list = LinkedList::new(); + // creo lista [50, 20, 10, 30, 40] + list.push_back(10); + list.push_front(20); + list.push_back(30); + list.push_back(40); + list.push_front(50); + + assert_eq!(5, list.len()); + // [50, 20, 10, 30, 40] + assert_eq!(Some(10), list.get(2)); + // [50, 20, 30, 40] + assert_eq!(Some(20), list.get(1)); + // [50, 30, 40] + assert_eq!(Some(30), list.get(1)); + // [30, 40] + assert_eq!(Some(40), list.get(1)); + // [30] + assert_eq!(Some(50), list.get(0)); + // [] + assert_eq!(None, list.get(0)); + assert_eq!(None, list.pop_back()); + assert_eq!(None, list.pop_front()); + assert_eq!(0, list.len()); + + // creo lista [50, 20, 10, 30, 40] + list.push_back(10); + list.push_front(20); + list.push_back(30); + list.push_back(40); + list.push_front(50); + + assert_eq!(5, list.len()); + assert_eq!(None, list.get(-6)); + assert_eq!(Some(50), list.get(-5)); + assert_eq!(4, list.len()); + assert_eq!(Some(20), list.get(-4)); + assert_eq!(3, list.len()); + assert_eq!(Some(10), list.get(-3)); + assert_eq!(2, list.len()); + assert_eq!(Some(30), list.get(-2)); + assert_eq!(1, list.len()); + assert_eq!(Some(40), list.get(-1)); + assert_eq!(None, list.get(-1)); + assert_eq!(0, list.len()); +}