Files
datastructures/sequential/linkedlist.hpp

191 lines
2.9 KiB
C++

#include <memory>
#include <stdexcept>
namespace List
{
template<class T>
struct Node
{
T value;
std::unique_ptr<Node<T>> next;
Node(T const & _value)
: value(_value),
next(nullptr)
{}
};
template<class T>
class List
{
protected:
std::unique_ptr<Node<T>> root;
Node<T> * tailPtr;
std::size_t size;
public:
void Append(T const value)
{
if(size == 0)
{
root = std::make_unique<Node<T>>(value);
tailPtr = root.get();
++size;
return;
}
tailPtr->next = std::make_unique<Node<T>>(value);
tailPtr = tailPtr->next.get();
++size;
}
void Prepend(T const value)
{
if(size == 0)
{
root = std::make_unique<Node<T>>(value);
tailPtr = root.get();
++size;
return;
}
auto newRoot = std::make_unique<Node<T>>(value);
newRoot->next.swap(root);
root.swap(newRoot);
++size;
}
void Insert(T const value, std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
if(index == 0u)
{
Prepend(value);
return;
}
++size;
Node<T> * prevPtr = root.get();
Node<T> * curPtr = root->next.get();
std::size_t currentIndex = 1u;
while(currentIndex < index)
{
prevPtr = curPtr;
curPtr = curPtr->next.get();
++currentIndex;
}
auto newNode = std::make_unique<Node<T>>(value);
newNode->next.swap(prevPtr->next);
prevPtr->next.swap(newNode);
}
void Delete(std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
--size;
if(index == 0u)
{
if(size == 0u)
{
root.release();
tailPtr = nullptr;
}
else
{
root = std::move(root->next);
}
return;
}
// Is index last element? Note that we subtracted 1 from size above
if(index == size)
{
Node<T> * curPtr = root.get();
while(curPtr->next.get() != tailPtr)
{
curPtr = curPtr->next.get();
}
tailPtr = curPtr;
tailPtr->next.release();
return;
}
Node<T> * prevPtr = root.get();
Node<T> * curPtr = prevPtr->next.get();
std::size_t currentIndex = 1u;
while(currentIndex < index)
{
++currentIndex;
prevPtr = curPtr;
curPtr = curPtr->next.get();
}
prevPtr->next = std::move(curPtr->next);
}
T & Front()
{
if(size == 0u)
{
throw std::out_of_range("List is empty.");
}
return root->value;
}
T & Back()
{
if(size == 0u)
{
throw std::out_of_range("List is empty.");
}
return tailPtr->value;
}
T & operator[](std::size_t const index)
{
if(index >= size)
{
throw std::out_of_range("Index is greater or equal to size.");
}
Node<T> * currentNode = root.get();
std::size_t currentIndex = 0u;
while(currentIndex < index)
{
currentNode = currentNode->next.get();
++currentIndex;
}
return currentNode->value;
}
std::size_t GetSize() const
{
return size;
}
List()
: root(nullptr),
tailPtr(nullptr),
size(0)
{}
};
}