From 497ab41504532e5a77e6511742604ad8249eb549 Mon Sep 17 00:00:00 2001 From: sikoeh <111141745+sikoeh@users.noreply.github.com> Date: Tue, 16 Aug 2022 12:37:54 +0200 Subject: [PATCH] added implementation of a single linked list --- .../single_linked_list/single_linked_list.cpp | 118 ++++++++++++ .../single_linked_list/single_linked_list.hpp | 172 ++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 data_structures/single_linked_list/single_linked_list.cpp create mode 100644 data_structures/single_linked_list/single_linked_list.hpp diff --git a/data_structures/single_linked_list/single_linked_list.cpp b/data_structures/single_linked_list/single_linked_list.cpp new file mode 100644 index 0000000..cefc5f2 --- /dev/null +++ b/data_structures/single_linked_list/single_linked_list.cpp @@ -0,0 +1,118 @@ +/* +* Author: sikoeh (https://github.com/sikoeh) +* +* Example usage of the single linked list. +* This file aims to test the size of the list and position of it's elements after the different operations. +* Zero memory leaks according to valgrind. +* Compiled and executed with following commands: +* > g++ single_linked_list.hpp +* > g++ single_linked_list.cpp +* > ./a.out +*/ + +#include "single_linked_list.hpp" + +#include + +//dummy that is used as list data for later tests +class dummy{ + public: + dummy(int x, int y) + : + x_(x), + y_(y) + {}; + + //simple compare of x and y values + bool operator ==(const dummy& other){ + bool res = x_ == other.x_; + res &= y_ == other.y_; + return res; + } + + private: + int x_; + int y_; +}; + + + +int main(){ + //Tests with simple integer + single_linked_list list; + + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + list.insert(5); + + assert(list.size() == 5); + assert(list.at(3) == 4); + + list.remove(4); + + assert(list.size() == 4); + assert(list.at(3) == 5); + + + + //Check for correct size after invalid position input + try{ + list.remove_at(200); + assert(false); + } + catch(const std::exception& e){ + assert(list.size() == 4); + } + + list.insert_at(0, 0); + assert(list.size() == 5); + assert(list.at(0) == 0); + + list.remove_at(0); + assert(list.size() == 4); + assert(list.at(0) == 1); + + list.insert_at(7, 3); + assert(list.size() == 5); + assert(list.at(3) == 7); + + list.remove_at(3); + assert(list.size() == 4); + assert(list.at(3) == 5); + + //Test copy constructor + single_linked_list copy(list); + + assert(copy.size() == 4); + assert(copy.at(3) == 5); + + //Test move constructor + single_linked_list move_list(std::move(copy)); + assert(move_list.size() == 4); + assert(move_list.at(3) == 5); + + //Tests with dummy class + single_linked_list list2; + + dummy d1(1, 2); + dummy d2(2, 3); + dummy d3(3, 4); + dummy d4(5, 6); + + list2.insert(d1); + list2.insert(d2); + list2.insert(d3); + list2.insert(d4); + + assert(list2.size() == 4); + assert(list2.at(0) == d1); + + list2.remove(d2); + + assert(list2.size() == 3); + assert(list2.at(1) == d3); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/data_structures/single_linked_list/single_linked_list.hpp b/data_structures/single_linked_list/single_linked_list.hpp new file mode 100644 index 0000000..e12ab16 --- /dev/null +++ b/data_structures/single_linked_list/single_linked_list.hpp @@ -0,0 +1,172 @@ +/* +* Author: sikoeh (https://github.com/sikoeh) +* +* Implementation of a simple single linked list with the help of templates. +* Objects stored in this list must have a copy-constructor and a valid == operator. +*/ +#ifndef INCLUDED_SINGLE_LINKED_LIST +#define INCLUDED_SINGLE_LINKED_LIST + +#include + +template +class single_linked_list{ + public: + + single_linked_list() + : + head_(nullptr), + size_(0) + {}; + + single_linked_list(const single_linked_list& other) + : + head_(nullptr), + size_(0) + { + list_element* iterator = other.head_; + while(iterator != nullptr){ + insert(iterator->data_); + iterator = iterator->next_; + } + }; + + single_linked_list(single_linked_list&& other) + : + head_(other.head_), + size_(other.size_) + { + other.head_ = nullptr; + other.size_ = 0; + }; + + + ~single_linked_list(){ + list_element* to_delete = head_; + while(to_delete != nullptr){ + head_ = to_delete->next_; + delete to_delete; + to_delete = head_; + } + }; + + //insert at the end + void insert(const T& element){ + list_element* new_element = new list_element(nullptr, element); + + if(head_ == nullptr){ + head_ = new_element; + ++size_; + return; + } + + list_element* iterator = head_; + while(iterator->next_ != nullptr) + iterator = iterator->next_; + + iterator->next_ = new_element; + ++size_; + }; + + //insert at the given position (0 is head) + void insert_at(const T& element, int position){ + if(position > size_ || position < 0){ + throw std::runtime_error("Invalid position"); + } + + if(position == 0){ + list_element* new_element = new list_element(head_, element); + head_ = new_element; + ++size_; + return; + } + + list_element* iterator = head_; + for (int i = 0; i < position-1; ++i) + { + iterator = iterator->next_; + } + + list_element* new_element = new list_element(iterator->next_, element); + iterator->next_ = new_element; + ++size_; + }; + + //remove the first element that is equal to the parameter (checked by == operator) + //does nothing in case there is no such element + void remove(const T& element){ + list_element* iterator = head_; + if(element == head_->data_){ + head_ = head_->next_; + delete iterator; + return; + } + + while (iterator != nullptr) + { + list_element* next_element = iterator->next_; + if(next_element->data_ == element){ + iterator->next_ = next_element->next_; + delete next_element; + --size_; + return; + } + iterator = iterator->next_; + } + }; + + //remove element at given position (0 is head) + void remove_at(int position){ + if(position < 0 || position >= size_) + throw std::runtime_error("Invalid position"); + + if(position == 0){ + list_element* new_head = head_->next_; + delete head_; + head_ = new_head; + --size_; + return; + } + + list_element* iterator = head_; + for(int i = 0; i < position - 1; ++i) + iterator = iterator->next_; + + list_element* to_delete = iterator->next_; + iterator->next_ = to_delete->next_; + delete to_delete; + --size_; + }; + + //return a reference to the element at the given position (0 is head) + T& at(int position) const{ + if(position < 0 || position >= size_) + throw std::runtime_error("Invalid position"); + + list_element* iterator = head_; + for(int i = 0; i < position; ++i){ + iterator = iterator->next_; + } + return iterator->data_; + }; + + int size() const{ + return size_; + }; + + private: + struct list_element{ + list_element(list_element* next, T data) + : + next_(next), + data_(data) + {}; + list_element* next_; + T data_; + }; + + list_element* head_; + int size_; +}; + +#endif \ No newline at end of file