Skip to content

Commit

Permalink
adt: add linked list (#12937)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hunam6 committed Dec 23, 2021
1 parent fa2de89 commit 54a6973
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions vlib/adt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ great variety of applications.
## implementations

- [x] Stack (LIFO)
- [x] Linked list
- [ ] ...
138 changes: 138 additions & 0 deletions vlib/adt/linked_list.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
module adt

pub struct ListNode<T> {
mut:
data T
next &ListNode<T> = 0
}

pub struct LinkedList<T> {
mut:
head &ListNode<T> = 0
len int
}

// is_empty checks if the linked list is empty
pub fn (list LinkedList<T>) is_empty() bool {
return list.len == 0
}

// len returns the length of the linked list
pub fn (list LinkedList<T>) len() int {
return list.len
}

// first returns the first element of the linked list
pub fn (list LinkedList<T>) first() ?T {
return if !list.is_empty() { list.head.data } else { error('Linked list is empty') }
}

// last returns the last element of the linked list
pub fn (list LinkedList<T>) last() ?T {
if list.head == 0 {
return error('Linked list is empty')
} else {
mut node := list.head
for node.next != 0 {
node = node.next
}
return node.data
}
}

// push adds an element to the end of the linked list
pub fn (mut list LinkedList<T>) push(item T) {
new_node := &ListNode{
data: item
}
if list.head == 0 {
// first node case
list.head = new_node
} else {
mut node := list.head
for node.next != 0 {
node = node.next
}
node.next = new_node
}
list.len += 1
}

// pop removes the last element of the linked list
pub fn (mut list LinkedList<T>) pop() ?T {
if list.head == 0 {
return error('Linked list is empty')
}
mut node := list.head
mut to_return := node.data
if node.next == 0 {
// first node case
// set to null
list.head = voidptr(0)
} else {
for node.next.next != 0 {
node = node.next
}
to_return = node.next.data
// set to null
node.next = voidptr(0)
}
list.len -= 1
return to_return
}

// shift removes the first element of the linked list
pub fn (mut list LinkedList<T>) shift() ?T {
if list.head == 0 {
return error('Linked list is empty')
} else {
list.len -= 1
node := list.head
list.head = node.next
return node.data
}
}

// insert adds an element to the linked list at the given index
pub fn (mut list LinkedList<T>) insert(idx int, item T) ? {
if idx < 0 || idx > list.len {
return error('Index out of bounds')
} else if list.len == 0 {
list.push(item)
} else {
list.len += 1
mut node := list.head

if idx == 0 {
// first node case
list.head = &ListNode{
data: item
next: node
}
} else {
for i := 0; i < idx - 1; i++ {
node = node.next
}
node.next = &ListNode{
data: item
next: node.next
}
}
}
}

// prepend adds an element to the beginning of the linked list (equivalent to insert(0, item))
pub fn (mut list LinkedList<T>) prepend(item T) {
list.insert(0, item) or {}
}

// str returns a string representation of the linked list
pub fn (list LinkedList<T>) str() string {
mut result_array := []T{}
mut node := list.head
for node != 0 {
result_array << node.data
node = node.next
}
return result_array.str()
}
103 changes: 103 additions & 0 deletions vlib/adt/linked_list_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
module adt

fn test_is_empty() {
mut list := LinkedList<int>{}
assert list.is_empty() == true
list.push(1)
assert list.is_empty() == false
}

fn test_len() ? {
mut list := LinkedList<int>{}
assert list.len() == 0
list.push(1)
assert list.len() == 1
list.pop() ?
assert list.len() == 0
}

fn test_first() ? {
mut list := LinkedList<int>{}
list.push(1)
assert list.first() ? == 1
list.push(2)
assert list.first() ? == 1
list = LinkedList<int>{}
list.first() or { return }
assert false
}

fn test_last() ? {
mut list := LinkedList<int>{}
list.push(1)
assert list.last() ? == 1
list.push(2)
assert list.last() ? == 2
list = LinkedList<int>{}
list.last() or { return }
assert false
}

fn test_push() ? {
mut list := LinkedList<int>{}
list.push(1)
assert list.last() ? == 1
list.push(2)
assert list.last() ? == 2
list.push(3)
assert list.last() ? == 3
}

fn test_pop() ? {
mut list := LinkedList<int>{}
list.push(1)
list.push(2)
list.push(3)
assert list.pop() ? == 3
list.push(4)
assert list.pop() ? == 4
assert list.pop() ? == 2
list = LinkedList<int>{}
list.pop() or { return }
assert false
}

fn test_shift() ? {
mut list := LinkedList<int>{}
list.push(1)
list.push(2)
list.push(3)
assert list.shift() ? == 1
list.push(4)
assert list.shift() ? == 2
assert list.shift() ? == 3
list = LinkedList<int>{}
list.shift() or { return }
assert false
}

fn test_insert() ? {
mut list := LinkedList<int>{}
list.push(1)
list.push(2)
list.push(3)
list.insert(1, 111) or { return }
assert true
}

fn test_prepend() ? {
mut list := LinkedList<int>{}
list.push(1)
list.push(2)
list.push(3)
list.prepend(111)
assert list.first() ? == 111
}

fn test_str() ? {
mut list := LinkedList<int>{}
list.push(1)
list.push(2)
list.push(3)
assert list.str() == '[1, 2, 3]'
}

0 comments on commit 54a6973

Please sign in to comment.