aboutsummaryrefslogtreecommitdiff
path: root/simple-linked-list/src
diff options
context:
space:
mode:
Diffstat (limited to 'simple-linked-list/src')
-rw-r--r--simple-linked-list/src/lib.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/simple-linked-list/src/lib.rs b/simple-linked-list/src/lib.rs
new file mode 100644
index 0000000..75e82f5
--- /dev/null
+++ b/simple-linked-list/src/lib.rs
@@ -0,0 +1,109 @@
1use std::iter::FromIterator;
2
3#[derive(Debug)]
4struct Node<T> {
5 data: T,
6 next: Option<Box<Node<T>>>,
7}
8
9impl<T> Node<T> {
10 pub fn new(data: T, next: Option<Box<Node<T>>>) -> Self {
11 Node { data, next }
12 }
13
14 pub fn len(&self) -> usize {
15 1 + self.next.as_ref().map(|n| n.len()).unwrap_or(0)
16 }
17}
18
19#[derive(Debug)]
20pub struct SimpleLinkedList<T> {
21 head: Option<Box<Node<T>>>,
22}
23
24impl<T> SimpleLinkedList<T> {
25 pub fn new() -> Self {
26 SimpleLinkedList { head: None }
27 }
28
29 // You may be wondering why it's necessary to have is_empty()
30 // when it can easily be determined from len().
31 // It's good custom to have both because len() can be expensive for some types,
32 // whereas is_empty() is almost always cheap.
33 // (Also ask yourself whether len() is expensive for SimpleLinkedList)
34 pub fn is_empty(&self) -> bool {
35 self.head.is_none()
36 }
37
38 pub fn len(&self) -> usize {
39 self.head.as_ref().map(|n| n.len()).unwrap_or(0)
40 }
41
42 pub fn push(&mut self, _element: T) {
43 // let node = Box::new(Node::new(_element, self.head.take()));
44 // self.head.replace(node);
45 self.head = Some(Box::new(Node::new(_element, self.head.take())));
46 }
47
48 pub fn pop(&mut self) -> Option<T> {
49 self.head.take().map(|n| {
50 // n.next.map(|n1| self.head.replace(n1));
51 self.head = n.next;
52 n.data
53 })
54 }
55
56 pub fn peek(&self) -> Option<&T> {
57 self.head.as_ref().map(|n| &n.data)
58 }
59
60 pub fn rev(self) -> SimpleLinkedList<T> {
61 self.rev_aux(SimpleLinkedList::new())
62 }
63
64 pub fn rev_aux(mut self, mut acc: SimpleLinkedList<T>) -> SimpleLinkedList<T> {
65 if let Some(e) = self.pop() {
66 acc.push(e);
67 self.rev_aux(acc)
68 } else {
69 acc
70 }
71 }
72
73 fn into_aux(mut self, mut acc: Vec<T>) -> Vec<T> {
74 if let Some(e) = self.pop() {
75 acc.push(e);
76 self.into_aux(acc)
77 } else {
78 acc
79 }
80 }
81}
82
83impl<T> FromIterator<T> for SimpleLinkedList<T> {
84 fn from_iter<I: IntoIterator<Item = T>>(_iter: I) -> Self {
85 _iter
86 .into_iter()
87 .fold(SimpleLinkedList::new(), |mut acc, n| {
88 acc.push(n);
89 acc
90 })
91 }
92}
93
94// In general, it would be preferable to implement IntoIterator for SimpleLinkedList<T>
95// instead of implementing an explicit conversion to a vector. This is because, together,
96// FromIterator and IntoIterator enable conversion between arbitrary collections.
97// Given that implementation, converting to a vector is trivial:
98//
99// let vec: Vec<_> = simple_linked_list.into_iter().collect();
100//
101// The reason this exercise's API includes an explicit conversion to Vec<T> instead
102// of IntoIterator is that implementing that interface is fairly complicated, and
103// demands more of the student than we expect at this point in the track.
104
105impl<T> Into<Vec<T>> for SimpleLinkedList<T> {
106 fn into(self) -> Vec<T> {
107 self.rev().into_aux(Vec::new())
108 }
109}