From 54a6973548a12c70d3256c4aa003439ed59de297 Mon Sep 17 00:00:00 2001 From: Hunam Date: Thu, 23 Dec 2021 17:23:04 +0100 Subject: [PATCH] adt: add linked list (#12937) --- vlib/adt/README.md | 1 + vlib/adt/linked_list.v | 138 ++++++++++++++++++++++++++++++++++++ vlib/adt/linked_list_test.v | 103 +++++++++++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 vlib/adt/linked_list.v create mode 100644 vlib/adt/linked_list_test.v diff --git a/vlib/adt/README.md b/vlib/adt/README.md index da6acd151d..92903eeb46 100644 --- a/vlib/adt/README.md +++ b/vlib/adt/README.md @@ -6,4 +6,5 @@ great variety of applications. ## implementations - [x] Stack (LIFO) +- [x] Linked list - [ ] ... diff --git a/vlib/adt/linked_list.v b/vlib/adt/linked_list.v new file mode 100644 index 0000000000..7855ee1f57 --- /dev/null +++ b/vlib/adt/linked_list.v @@ -0,0 +1,138 @@ +module adt + +pub struct ListNode { +mut: + data T + next &ListNode = 0 +} + +pub struct LinkedList { +mut: + head &ListNode = 0 + len int +} + +// is_empty checks if the linked list is empty +pub fn (list LinkedList) is_empty() bool { + return list.len == 0 +} + +// len returns the length of the linked list +pub fn (list LinkedList) len() int { + return list.len +} + +// first returns the first element of the linked list +pub fn (list LinkedList) 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) 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) 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) 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) 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) 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) prepend(item T) { + list.insert(0, item) or {} +} + +// str returns a string representation of the linked list +pub fn (list LinkedList) str() string { + mut result_array := []T{} + mut node := list.head + for node != 0 { + result_array << node.data + node = node.next + } + return result_array.str() +} diff --git a/vlib/adt/linked_list_test.v b/vlib/adt/linked_list_test.v new file mode 100644 index 0000000000..0e66be05d7 --- /dev/null +++ b/vlib/adt/linked_list_test.v @@ -0,0 +1,103 @@ +module adt + +fn test_is_empty() { + mut list := LinkedList{} + assert list.is_empty() == true + list.push(1) + assert list.is_empty() == false +} + +fn test_len() ? { + mut list := LinkedList{} + assert list.len() == 0 + list.push(1) + assert list.len() == 1 + list.pop() ? + assert list.len() == 0 +} + +fn test_first() ? { + mut list := LinkedList{} + list.push(1) + assert list.first() ? == 1 + list.push(2) + assert list.first() ? == 1 + list = LinkedList{} + list.first() or { return } + assert false +} + +fn test_last() ? { + mut list := LinkedList{} + list.push(1) + assert list.last() ? == 1 + list.push(2) + assert list.last() ? == 2 + list = LinkedList{} + list.last() or { return } + assert false +} + +fn test_push() ? { + mut list := LinkedList{} + 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{} + 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{} + list.pop() or { return } + assert false +} + +fn test_shift() ? { + mut list := LinkedList{} + 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{} + list.shift() or { return } + assert false +} + +fn test_insert() ? { + mut list := LinkedList{} + list.push(1) + list.push(2) + list.push(3) + list.insert(1, 111) or { return } + assert true +} + +fn test_prepend() ? { + mut list := LinkedList{} + list.push(1) + list.push(2) + list.push(3) + list.prepend(111) + assert list.first() ? == 111 +} + +fn test_str() ? { + mut list := LinkedList{} + list.push(1) + list.push(2) + list.push(3) + assert list.str() == '[1, 2, 3]' +}