Skip to content

Commit

Permalink
Merge pull request #23 from sikoeh/single-linked-list
Browse files Browse the repository at this point in the history
added implementation of a single linked list
  • Loading branch information
ademclk authored Aug 16, 2022
2 parents ed9dcb8 + 497ab41 commit 127849e
Show file tree
Hide file tree
Showing 2 changed files with 290 additions and 0 deletions.
118 changes: 118 additions & 0 deletions data_structures/single_linked_list/single_linked_list.cpp
Original file line number Diff line number Diff line change
@@ -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 <cassert>

//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<int> 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<int> copy(list);

assert(copy.size() == 4);
assert(copy.at(3) == 5);

//Test move constructor
single_linked_list<int> move_list(std::move(copy));
assert(move_list.size() == 4);
assert(move_list.at(3) == 5);

//Tests with dummy class
single_linked_list<dummy&> 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;
}
172 changes: 172 additions & 0 deletions data_structures/single_linked_list/single_linked_list.hpp
Original file line number Diff line number Diff line change
@@ -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 <stdexcept>

template<class T>
class single_linked_list{
public:

single_linked_list()
:
head_(nullptr),
size_(0)
{};

single_linked_list(const single_linked_list<T>& 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<T>&& 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

0 comments on commit 127849e

Please sign in to comment.