Files
CPP-LinkedList/include/linkedlist.h

416 lines
9.5 KiB
C++

#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <concepts>
#include <cstdlib>
#include <expected>
#include <format>
#include <new>
#include <print>
template <typename T>
concept HasEqual = requires (T a, T b) {
{a == b} -> std::convertible_to<bool>;
};
template <typename T>
concept LinkedListSupported =
std::formattable<T, char> &&
std::equality_comparable<T> &&
HasEqual<T>;
/**
* @brief Codigos de error para operaciones de LinkedList
*/
enum class LinkedListErr {
LINKEDLIST_OK, /**< Operacin exitosa */
LINKEDLIST_BAD_ALLOC, /**< Error al asignar memoria */
LINKEDLIST_OUT_OF_BOUNDS, /**< Índice fuera de rango */
LINKESLIST_INVALID_SIZE, /**< Tamaño inválido */
LINKEDLIST_NOT_FOUND, /**< Elemento no encontrado */
LINKEDLIST_EMPTY, /**< La lista está vacia */
};
/**
* @brief Nodo de una lista enlazada
*
* @tparam T Tipo de dato almacenado en el nodo
*/
template<LinkedListSupported T>
class Node {
public:
T data; /**< Dato almacenado en el nodo */
Node<T> *next; /**< Puntero al siguiente nodo */
};
/**
* @brief Implementación de una lista enlazada simple
*
* Estructura de datos dinamica que almacena elementos de tipo T
* utilizando nodos enlazados mediante punteros.
*
* @tparam T Tipo de dato almacenado en la lista
*/
template<LinkedListSupported T>
class LinkedList {
private:
size_t size; /**< Numero de elementos en la lista */
Node<T> *head; /**< Primer nodo de la lista */
Node<T> *tail; /**< Último nodo de la lista */
public:
/**
* @brief Constructor de la lista enlazada
*/
LinkedList();
/**
* @brief Destructor de la lista
*
* Libera toda la memoria de los nodos.
*/
~LinkedList();
/**
* @brief Obtiene el elemento en una posicion específica
*
* @param index indice del elemento
* @return std::expected<T, LinkedListErr> Valor encontrado o error
*/
std::expected<T, LinkedListErr> get(size_t index);
/**
* @brief Inserta un elemento al final de la lista
*
* @param value Valor a insertar
* @return LinkedListErr Cdigo de estado de la operacion
*/
LinkedListErr append(const T& value);
/**
* @brief Inserta un elemento al inicio de la lista
*
* @param value Valor a insertar
* @return LinkedListErr Codigo de estado
*/
LinkedListErr prepend(const T& value);
/**
* @brief Elimina y devuelve el ultimo elemento de la lista
*
* @return std::expected<T, LinkedListErr> Elemento eliminado o error
*/
std::expected<T, LinkedListErr> pop();
/**
* @brief Elimina el elemento en una posicion especifica
*
* @param index Indice del elemento a eliminar
* @return LinkedListErr Codigo de estado
*/
LinkedListErr remove(size_t index);
/**
* @brief Modifica el valor de un elemento en un indice
*
* @param index Índice del elemento
* @param value Nuevo valor
* @return LinkedListErr Código de estado
*/
LinkedListErr set(size_t index, const T& value);
/**
* @brief Inserta un valor en el index dado.
*
* @param index Indice del elemento
* @param value Nuevo valor
* @return LinkedListErr Codigo de estado
*/
LinkedListErr insert (size_t index, const T& value);
/**
* @brief Busca un valor dentro de la lista
*
* @param value Valor a buscar
* @return std::expected<size_t, LinkedListErr> Índice del elemento o error
*/
std::expected<size_t, LinkedListErr> find(const T& value);
/**
* @brief Imprime los elementos de la lista
*
* @return LinkedListErr Código de estado
*/
LinkedListErr print();
/**
* @brief Verifica si la lista esta vacia
*
* @return true si la lista no contiene elementos
*/
bool is_empty();
/**
* @brief Obtiene el numero de elementos de la lista
*
* @return size_t Tamaño de la lista
*/
size_t len();
};
template <LinkedListSupported T>
LinkedList<T>::LinkedList() {
size = 0;
head = nullptr;
tail = nullptr;
}
template <LinkedListSupported T>
LinkedList<T>::~LinkedList() {
Node<T> *current = this->head;
while (current != nullptr) {
Node<T> *temp = current;
current = current->next;
delete temp;
}
}
template <LinkedListSupported T>
std::expected<T, LinkedListErr> LinkedList<T>::get(size_t index) {
if (index >= this->size) {
return std::unexpected(LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS);
}
if (index == this->size - 1) {
return tail->data;
}
Node<T> *current = this->head;
for (size_t i = 0; i < index ; i++) {
current = current->next;
}
return current->data;
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::set(size_t index, const T& val) {
if (index >= this->size) {
return LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS;
}
if (index == this->size - 1) {
this->tail->data = val;
}
Node<T> *current = this->head;
for (size_t i = 0; i < index; i++) {
current = current->next;
}
current->data = val;
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::insert(size_t index, const T& value) {
if (this->is_empty()) {
return this->append(value);
}
if (index >= this->size) {
return LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS;
}
// If index is head
if (index == 0) {
return this->prepend(value);
}
// If index is tail
if (index == this->size - 1) {
return this->append(value);
}
Node<T> *current = this->head;
for (size_t i = 1; i < index; i++) {
current = current->next;
}
Node<T> *new_node = nullptr;
try {
new_node = new Node<T>;
} catch(const std::bad_alloc&) {
return LinkedListErr::LINKEDLIST_BAD_ALLOC;
}
new_node->data = value;
new_node->next = current->next->next;
current->next = new_node;
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::append(const T& value) {
Node<T> *new_node = nullptr;
try {
new_node = new Node<T>;
} catch(std::bad_alloc&) {
return LinkedListErr::LINKEDLIST_BAD_ALLOC;
}
new_node->data = value;
new_node->next = nullptr;
if (this->head == nullptr && this->tail == nullptr) {
this->head = new_node;
this->tail = this->head;
} else {
this->tail->next = new_node;
this->tail = this->tail->next;
}
this->size += 1;
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::prepend(const T& value) {
Node<T> *new_node = nullptr;
try {
new_node = new Node<T>;
} catch(std::bad_alloc&) {
return LinkedListErr::LINKEDLIST_BAD_ALLOC;
}
new_node->data = value;
new_node->next = nullptr;
if (this->head == nullptr && this->tail == nullptr) {
this->head = new_node;
this->tail = this->head;
} else {
new_node->next = this->head;
this->head = new_node;
}
this->size += 1;
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
std::expected<T, LinkedListErr> LinkedList<T>::pop() {
if (this->size == 0) {
return std::unexpected(LinkedListErr::LINKEDLIST_EMPTY);
}
if (this->head->next == nullptr) {
T return_val = this->head->data;
delete this->head;
this->head = nullptr;
this->size--;
return return_val;
}
Node<T>* current = this->head;
while (current->next->next != nullptr) {
current = current->next;
}
T return_val = current->next->data;
delete current->next;
current->next = nullptr;
this->size--;
return return_val;
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::remove(size_t index) {
if (index >= this->size) {
return LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS;
}
if (index == 0) {
Node<T>* tmp = this->head;
this->head = this->head->next;
delete tmp;
this->size--;
return LinkedListErr::LINKEDLIST_OK;
}
Node<T>* current = this->head;
for (size_t i = 1; i < index; ++i) {
current = current->next;
}
Node<T>* tmp = current->next;
current->next = tmp->next;
if(tmp == this->tail) {
this->tail = current;
}
delete tmp;
this->size--;
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
std::expected<size_t, LinkedListErr> LinkedList<T>::find(const T& value) {
Node<T> *current = this->head;
size_t count = 0;
while (current != nullptr) {
if (current->data == value) {
return count;
}
count++;
current = current->next;
}
return std::unexpected(LinkedListErr::LINKEDLIST_NOT_FOUND);
}
template <LinkedListSupported T>
LinkedListErr LinkedList<T>::print() {
if (this->size == 0) {
return LinkedListErr::LINKEDLIST_OK;
}
std::println("[LL]");
std::println(" |\n v");
Node<T> *current = this->head;
while (current != nullptr) {
std::println("Node({})", current->data);
std::println(" |");
std::println(" v");
current = current->next;
}
std::println("NULL");
return LinkedListErr::LINKEDLIST_OK;
}
template <LinkedListSupported T>
size_t LinkedList<T>::len() {
return this->size;
}
#endif // !