From e79238892771d5728e9ba9e09b9fd628332e8a98 Mon Sep 17 00:00:00 2001 From: SleepiCaffeine Date: Sat, 24 Jun 2023 00:16:15 +0300 Subject: [PATCH] Removed tail ptrs, fixed up funcs, added comments --- Data Structures/dl_list.hpp | 396 +++++------------------------------ Data Structures/sl_list.hpp | 407 +++++++----------------------------- 2 files changed, 127 insertions(+), 676 deletions(-) diff --git a/Data Structures/dl_list.hpp b/Data Structures/dl_list.hpp index 1516f4e..159215e 100644 --- a/Data Structures/dl_list.hpp +++ b/Data Structures/dl_list.hpp @@ -1,9 +1,9 @@ /** - * @file dl_list.h + * @file dl_list.hpp * @author Vakaris Michejenko (sleepicaffeine@gmail.com) * @brief A header that defines a dynamic Doubly-linked list class - * @version 0.1 - * @date 2023-06-20 + * @version 0.3 + * @date 2023-06-24 * @copyright Copyright (c) 2023 * @link https://github.com/SleepiCaffeine */ @@ -22,8 +22,6 @@ * * @fn get_head() * @fn set_head(double_node* const nd) - * @fn get_tail() - * @fn set_tail(double_node* const nd) * * @fn push_front(double_node* const nd) * @fn push_front(const T dt) @@ -35,106 +33,32 @@ * @fn pop_front() * @fn pop_back() * - * @fn get_data() - * @fn set_data(T dt) - * - * @fn length() * @fn size() - * @fn update_len() - * @tparam T typename + * @tparam T class */ -template +template class dl_list { private: double_node* head; /**< Pointer to the head (or root) node [double_node*]*/ - double_node* tail; /**< Pointer to the tail node [double_node*]*/ unsigned int len; /**< List's length [unsigned int]*/ public: /** * Creates a new sl-list with a head and tail that points to NULL, and has a length of 0 * @brief Default constructor. - * @see ~dl_list() - * @see dl_list(double_node* const nd) * @see dl_list(const double_node& nd) - * @see dl_list(double_node* const hnd, double_node* const tnd) */ dl_list() : head{nullptr}, tail{nullptr}, len{0} {} - /** - * Creates a new sl-list with a head node - * @brief Constructor. - * @see dl_list() - * @see ~dl_list() - * @see dl_list(const double_node& nd) - * @see dl_list(double_node* const hnd, double_node* const tnd) - */ - dl_list(double_node* const nd) - : head{nd}, len{1} { - // If the head is the only node - if (nd->get_next() == nullptr) { - tail = nd; - return; - } - - // Traverse the list to get the correct length - double_node* currNode = new double_node(*nd); - while(currNode->get_next() != nullptr) { - ++len; - currNode = currNode->get_next(); - } - - // Set the tail to be the end node - tail = currNode; - } - - /** - * Creates a new sl-list with a head node, and a tail node - * @brief Constructor. - * @see dl_list() - * @see ~dl_list() - * @see dl_list(double_node* const nd) - * @see dl_list(const double_node& nd) - */ - dl_list(double_node* const hnd, double_node* const tnd) - : head{hnd}, tail{tnd}, len{1} { - // If the head is null - if (head == nullptr) { - tail = nullptr; - len = 0; - return; - } - - // Traverse the list until we reach the tail to get the correct length - double_node* currNode = new double_node(*hnd); - while(currNode != tnd) { - ++len; - currNode = currNode->get_next(); - } - } - /** * Constructs a new sl-list from another dl_list object * @brief Copy constructor. * @see dl_list() - * @see ~dl_list() - * @see dl_list(double_node* const nd) - * @see dl_list(const double_node& nd) */ dl_list(const dl_list& list); - /** - * Destroys the dl_list object - * @brief Destructor. - * @see dl_list() - * @see dl_list(double_node* const nd) - * @see dl_list(const double_node& nd) - * @see dl_list(double_node* const hnd, double_node* const tnd) - */ - ~dl_list(); - /** * Adds a node with the provided value to the end of the list * @param T node data @@ -214,31 +138,6 @@ class dl_list { */ void set_head(T dt); - /** - * Returns the tail of the dl_list - * @returns Tail node - * @see set_tail(T dt) - * @see set_tail(double_node* const nd) - * */ - double_node* get_tail() const; - - /** - * Sets the tail of the dl_list to the provided node - * @note This may ruin the list, be careful. If you want to swap values, look at void dl_list::set_tail(T dt) - * @param nd Node to be set as the tail node - * @see set_tail(T dt) - * @see get_tail() - * */ - void set_tail(double_node* const nd); - - /** - * Sets the data of the tail of the dl_list to the provided data value - * @param dt The new data value the tail will store - * @see set_tail(double_node* const nd) - * @see get_tail() - * */ - void set_tail(T dt); - /** * Inserts the Node into the index provided * @param nd Node to be inserted @@ -254,254 +153,108 @@ class dl_list { * @return Pointer to the Node that is behind the inserted Node */ double_node* insert_node(T dt, unsigned int idx); - - /** - * Returns the length of the sl list - * @return Length of LL - * @see size() - */ - unsigned int length() { - update_len(); - return len;} - - /** - * Returns the length of the sl list - * @return Length of LL - * @see length() - */ - unsigned int size() { - update_len(); - return len;} - /** - * Updates the length of the sl_list (Mainly kept to avoid bugs, will later implement other features to avoid using this) + * Returns the length of the dl list + * @return Length of the list */ - void update_len() { - len = 0; - double_node* currNode = new double_node(*(this->get_head())); - while (currNode != nullptr) { - currNode = currNode->get_next(); - ++len; - } - } + unsigned int size() {return len;} }; -template -dl_list::~dl_list() { - while (head) - head = head->get_next(); - - delete head; -} - -template +template dl_list::dl_list(const dl_list& list) { - len = list.length(); - - if (list.get_head() == nullptr) - return; - - // Recreate the head - double_node* newHead = new double_node(); - newHead->set_data(list.get_head()->get_data()); - head = newHead; - - // Deep-copy the remaining chain - double_node* currNode = head; - double_node* sourceNode = list.get_head()->get_next(); - - while(sourceNode->get_next() != nullptr) { - // Create a new Node in the list - currNode->set_next(new double_node()); - // Set its value to source value - currNode->get_next()->set_data(sourceNode->get_data()); - // Set the destination to null - currNode->get_next()->set_next(nullptr); - // Move over by one Node in the list - currNode = currNode->get_next(); - // Move over by one Node in the source - sourceNode = sourceNode->get_next(); - } - - currNode->set_next(tail); - tail = new double_node(*sourceNode); + len = list.len; + double_node* newNd = new double_node(*(list.get_head())); + head = newNd; }; -template +template double_node* dl_list::push_front(T dt) { - // If the list has a length of 0, create a node for the head, and set the tail to nullptr - if (!len) { - head = new double_node(dt); - tail = nullptr; - ++len; - return head; - } - - if (len == 1) { - tail = head; - head = new double_node(dt); - head->set_next(tail); - tail->set_prev(head); - ++len; - return head; - } - // Create a new head object with the provided data and pointing to the head itself - head = new double_node(head, dt); - ++len; - return head; + return push_front(new double_node(dt)); } -template +template double_node* dl_list::push_front(double_node* const nd) { - // If the list has a length of 0, create a node for the head, and set the tail to nullptr - if (!len) { - head = new double_node(*nd); - tail = nullptr; - ++len; - return head; - } - - if (len == 1) { - tail = head; - head = new double_node(*nd); - head->set_next(tail); - tail->set_prev(head); - ++len; - return head; - } - - // Swap head and provided node - auto oldHead = new double_node(*head); - oldHead->set_prev(nd); - nd->set_next(oldHead); - head = new double_node(*nd); + // Create new node to insert + double_node* newNode = new double_node(); + // Make new head + newNode->set_data(nd->get_data()); + newNode->set_next(head); + + // Replace old head with new + head = newNode; ++len; + return head; } -template +template double_node* dl_list::push_back(T dt) { - // If the list is empty, set both the head and tail to be the inserted node - if (!len) { - head = new double_node(dt); - tail = nullptr; - ++len; - return head; - } - - if (len == 1) { - tail = new double_node(dt); - head->set_next(tail); - tail->set_prev(head); - ++len; - return head; - } - - double_node* currNode = head; - double_node* newTail = new double_node(dt); - double_node* oldTail = new double_node(newTail, tail->get_prev(), tail->get_data()); - newTail->set_prev(oldTail); - tail = newTail; - - // Traverse the list - while (currNode->get_next()->get_next() != nullptr) - currNode = currNode->get_next(); - - // Add the Node to the end - currNode->set_next(oldTail); - ++len; - - return tail; + return push_back(new double_node(dt)); } -template +template double_node* dl_list::push_back(double_node* const nd) { - // If the list is empty, then set both the head and the tail to the parameter node - if (!len) { - head = new double_node(*nd); - tail = nullptr; - ++len; - return head; - } - - else if (len == 1) { - tail = new double_node(*nd); - head->set_next(tail); - tail->set_prev(head); - ++len; - return tail; - } - + // Set pointer node double_node* currNode = head; - double_node* oldTail = new double_node(*tail); - oldTail->set_next(nd); - - nd->set_prev(oldTail); - tail = nd; + double_node* newTail = new double_node(nd->get_data()); // Traverse the list - while (currNode->get_next()->get_next() != nullptr) + while (currNode->get_next() != nullptr) currNode = currNode->get_next(); // Add the Node to the end - currNode->set_next(oldTail); + currNode->set_next(newTail); + newTail->set_prev(currNode); ++len; - // Return the tail - return tail; + // Return the new "tail" + return newTail; } -template +template double_node* dl_list::pop_back() { + // Error case if (len <= 0) { - len = 0; - return nullptr; + throw std::invalid_argument("Invalid removal. List length is 0.\n"); } else if (len == 1) { --len; - head = nullptr; + delete head; return nullptr; } - double_node* currNode = head; + // Set pointer node + node* currNode = head; // Traversing until the second-to-last list Node while (currNode->get_next()->get_next() != nullptr) currNode = currNode->get_next(); // Set last list member to null + delete(currNode->get_next()); currNode->set_next(nullptr); - tail = currNode; - --len; // Return the new last member - return tail; + return currNode; } -template +template double_node* dl_list::pop_front() { - if (len <= 0) { - len = 0; - return nullptr; - } - - else if (len == 1) { - --len; - delete head; - delete tail; - return nullptr; - } + // Self-explanatory + if (head == nullptr) + return nullptr; + // Move over head by one node, and return it + node* temp = head; head = head->get_next(); - head->set_prev(nullptr); - --len; + delete temp; return head; } -template +template double_node* dl_list::insert_node(double_node* const nd, unsigned int idx) { if (idx == 0) { this->push_front(nd); @@ -527,65 +280,28 @@ double_node* dl_list::insert_node(double_node* const nd, unsigned int i ++len; - return nd; + return currentNode; } -template +template double_node* dl_list::insert_node(const T dt, unsigned int idx) { - if (idx == 0) { - this->push_front(dt); - return head; - } - - else if (idx >= this->size()) - throw std::invalid_argument("Provided index exceeds list length. Use push_back().\n"); - - double_node* currentNode = head; - unsigned int counter = 0; - while (counter < idx - 1) { - currentNode = currentNode->get_next(); - ++counter; - } - auto insertedNode = new double_node(currentNode->get_next(), dt); - - currentNode->set_next(insertedNode); - insertedNode->set_prev(currentNode); - ++len; - - return currentNode->get_next(); + return insert_node(new double_node(dt), idx); } -template +template double_node* dl_list::get_head() const { return head; } -template +template void dl_list::set_head(double_node* const nd) { head = nd; } -template +template void dl_list::set_head(T dt) { this->pop_front(); this->push_front(dt); } -template -double_node* dl_list::get_tail() const { - return tail; -} - -template -void dl_list::set_tail(double_node* const nd) { - this->pop_back(); - this->push_back(nd); -} - -template -void dl_list::set_tail(T dt) { - this->pop_back(); - this->push_back(dt); -} - #endif // DOUBLY_LINKED_LIST_H \ No newline at end of file diff --git a/Data Structures/sl_list.hpp b/Data Structures/sl_list.hpp index 427cec0..700eb6c 100644 --- a/Data Structures/sl_list.hpp +++ b/Data Structures/sl_list.hpp @@ -1,9 +1,9 @@ /** - * @file sl_list.h + * @file sl_list.hpp * @author Vakaris Michejenko (sleepicaffeine@gmail.com) * @brief A header that defines a dynamic singly-linked list class - * @version 0.2 - * @date 2023-06-20 + * @version 0.3 + * @date 2023-06-24 * @copyright Copyright (c) 2023 * @link https://github.com/SleepiCaffeine */ @@ -21,8 +21,6 @@ * * @fn get_head() * @fn set_head(node* const nd) - * @fn get_tail() - * @fn set_tail(node* const nd) * * @fn push_front(node* const nd) * @fn push_front(const T dt) @@ -34,104 +32,32 @@ * @fn pop_front() * @fn pop_back() * - * @fn length() * @fn size() - * @fn upadate_len() - * @tparam T typename + * @tparam T class */ -template +template class sl_list { private: - node* head; /**< Pointer to the head (or root) node [node*]*/ - node* tail; /**< Pointer to the tail node [node*]*/ + node* head; /**< Pointer to the head node [node*]*/ unsigned int len; /**< List's length [unsigned int]*/ public: /** * Creates a new sl-list with a head and tail that points to NULL, and has a length of 0 * @brief Default constructor. - * @see ~sl_list() - * @see sl_list(node* const nd) - * @see sl_list(const node& nd) - * @see sl_list(node* const hnd, node* const tnd) + * @see sl_list(const sl_list& list) */ sl_list() - : sl_list{nullptr, nullptr} {} - - /** - * Creates a new sl-list with a head node - * @brief Constructor. - * @see sl_list() - * @see ~sl_list() - * @see sl_list(const node& nd) - * @see sl_list(node* const hnd, node* const tnd) - */ - sl_list(node* const nd) - : head{nd}, len{1} { - // If the head is the only node - if (nd->get_next() == nullptr) { - tail = nullptr; - return; - } - - // Traverse the list to get the correct length - node* currNode = new node(*nd); - while(currNode->get_next() != nullptr) { - ++len; - currNode = currNode->get_next(); - } - - // Set the tail to be the end node - tail = currNode; - } - - /** - * Creates a new sl-list with a head node, and a tail node - * @brief Constructor. - * @see sl_list() - * @see ~sl_list() - * @see sl_list(node* const nd) - * @see sl_list(const node& nd) - */ - sl_list(node* const hnd, node* const tnd) - : head{hnd}, tail{tnd}, len{1} { - // Added to avoid any future issues with poor definitions - if (hnd == nullptr || tnd == nullptr) { - head = nullptr; - tail = nullptr; - len = 0; - return; - } - - // Traverse the list until we reach the tail to get the correct length - node* currNode = new node(*hnd); - while(currNode != tnd) { - ++len; - currNode = currNode->get_next(); - } - } + : head{nullptr}, len{0} { } /** * Constructs a new sl-list from another sl_list object * @brief Copy constructor. * @see sl_list() - * @see ~sl_list() - * @see sl_list(node* const nd) - * @see sl_list(const node& nd) */ sl_list(const sl_list& list); - /** - * Destroys the sl_list object - * @brief Destructor. - * @see sl_list() - * @see sl_list(node* const nd) - * @see sl_list(const node& nd) - * @see sl_list(node* const hnd, node* const tnd) - */ - ~sl_list(); - /** * Adds a node with the provided value to the end of the list * @param T node data @@ -174,7 +100,7 @@ class sl_list { /** * Removes a node from the end of the list - * @returns The list's new tail + * @returns The list's last node * @see pop_front() * */ node* pop_back(); @@ -196,7 +122,7 @@ class sl_list { /** * Sets the provided node to be the list's head - * @note This may ruin the list, be careful. If you want to swap values, look at void sl_list::set_head(T dt) + * @note This may ruin the list, be careful. If you want to swap values, look at sl_list::set_head(T dt) * @param nd Node to be the new head * @see set_head(T dt) * @see get_head() @@ -211,31 +137,6 @@ class sl_list { */ void set_head(T dt); - /** - * Returns the tail of the sl_list - * @returns Tail node - * @see set_tail(T dt) - * @see set_tail(node* const nd) - * */ - node* get_tail() const; - - /** - * Sets the tail of the sl_list to the provided node - * @note This may ruin the list, be careful. If you want to swap values, look at void sl_list::set_tail(T dt) - * @param nd Node to be set as the tail node - * @see set_tail(T dt) - * @see get_tail() - * */ - void set_tail(node* const nd); - - /** - * Sets the data of the tail of the sl_list to the provided data value - * @param dt The new data value the tail will store - * @see set_tail(node* const nd) - * @see get_tail() - * */ - void set_tail(T dt); - /** * Inserts the Node into the index provided * @param nd Node to be inserted @@ -252,211 +153,81 @@ class sl_list { */ node* insert_node(T dt, unsigned int idx); - /** - * Returns the length of the sl_list - * @return Length of the singly-linked list - * @see size() - */ - unsigned int length() { - update_len(); - return len; - } - /** * Returns the length of the sl_list * @return Length of the singly-linked list * @see length() */ unsigned int size() { - update_len(); return len; } - - /** - * Updates the length of the sl_list (Mainly kept to avoid bugs, will later implement other features to avoid using this) - */ - void update_len() { - len = 0; - node* currNode = new node(*(this->get_head())); - while (currNode != nullptr) { - currNode = currNode->get_next(); - ++len; - } - } }; -template -sl_list::~sl_list() { - while (head) - head = head->get_next(); - - delete head; -} - -template +template sl_list::sl_list(const sl_list& list) { - len = list.length(); - - if (list.get_head() == nullptr) - return; - - // Recreate the head - node* newHead = new node(); - newHead->set_data(list.get_head()->get_data()); - head = newHead; - - // Deep-copy the remaining chain - node* currNode = head; - node* sourceNode = list.get_head()->get_next(); - - while(sourceNode->get_next() != nullptr) { - // Create a new Node in the list - currNode->set_next(new node()); - // Set its value to source value - currNode->get_next()->set_data(sourceNode->get_data()); - // Set the destination to null - currNode->get_next()->set_next(nullptr); - // Move over by one Node in the list - currNode = currNode->get_next(); - // Move over by one Node in the source - sourceNode = sourceNode->get_next(); - } - - currNode->set_next(tail); - tail = new node(*sourceNode); + len = list.len; + head = list.head; }; -template +template node* sl_list::push_front(T dt) { - // If the list has a length of 0, set the list's head and tail to the same node - if (!len) { - node* newNode = new node(dt); - head = newNode; - tail = newNode; - ++len; - return head; - } - - if (len == 1) { - tail = head; - head = new node(dt); - head->set_next(tail); - ++len; - return head; - } - - // Create a new head object with the provided data and pointing to the head itself - head = new node(head, dt); - ++len; - return head; + // Delagate action to more precise function + return push_front(new node(dt)); } -template +template node* sl_list::push_front(node* const nd) { - // If the list has a length of 0, set the list's head and tail to the same node - if (!len) { - head = nd; - tail = nullptr; - ++len; - return head; - } + // Create new node to insert + node* newNode = new node(); - if (len == 1) { - tail = head; - head = new node(*nd); - head->set_next(tail); - ++len; - return head; - } + // Make new head + newNode->set_data(nd->get_data()); + newNode->set_next(head); - // Swap head and nd - auto oldHead = head; - nd->set_next(oldHead); - head = nd; + // Replace old head with new + head = newNode; ++len; - return nd; + + return head; } -template +template node* sl_list::push_back(T dt) { - // If the list is empty, set both the head and tail to be the inserted node - if (!len) { - head = new node(dt); - tail = nullptr; - ++len; - return head; - } - - else if (len == 1) { - tail = new node(dt); - head->set_next(tail); - ++len; - return tail; - } - - node* currNode = head; - node* newTail = new node(dt); - node* oldTail = new node(newTail, tail->get_data()); - tail = newTail; - - // Traverse the list - while (currNode->get_next()->get_next() != nullptr) - currNode = currNode->get_next(); - - // Add the Node to the end - currNode->set_next(oldTail); - ++len; - - return tail; + // Delagate action to more precise function + return push_back(new node(dt)); } -template +template node* sl_list::push_back(node* const nd) { - // If the list is empty, then set both the head and the tail to the parameter node - if (!len) { - head = new node(*nd); - tail = nullptr; - ++len; - return head; - } - - else if (len == 1) { - tail = new node(*nd); - head->set_next(tail); - ++len; - return tail; - } - + // Set pointer node node* currNode = head; - node* oldTail = new node(nd, tail->get_data()); - tail = nd; - + node* newTail = new node(nd->get_next(), nd->get_data()); // Traverse the list - while (currNode->get_next()->get_next() != nullptr) + while (currNode->get_next() != nullptr) currNode = currNode->get_next(); // Add the Node to the end - currNode->set_next(oldTail); + currNode->set_next(newTail); ++len; - // Return the tail - return tail; + // Return the new "tail" + return newTail; } -template +template node* sl_list::pop_back() { + // Error case if (len <= 0) { - len = 0; - return nullptr; + throw std::invalid_argument("Invalid removal. List length is 0.\n"); } else if (len == 1) { --len; - head = nullptr; - tail = nullptr; + delete head; return nullptr; } + // Set pointer node node* currNode = head; // Traversing until the second-to-last list Node @@ -464,115 +235,79 @@ node* sl_list::pop_back() { currNode = currNode->get_next(); // Set last list member to null + delete(currNode->get_next()); currNode->set_next(nullptr); - tail = currNode; - --len; // Return the new last member - return tail; + return currNode; } -template +template node* sl_list::pop_front() { - if (len <= 0) { - len = 0; - return nullptr; - } - - if (len == 1) { - --len; - delete head; - delete tail; - return nullptr; - } + // Self-explanatory + if (head == nullptr) + return nullptr; + // Move over head by one node, and return it + node* temp = head; head = head->get_next(); - --len; + delete temp; return head; } -template +template node* sl_list::insert_node(node* const nd, unsigned int idx) { + // Delegate to push_front, since that's already implemented if (idx == 0) { this->push_front(nd); return head; - } + } + // Out of range check else if (idx >= this->size()) { - throw std::invalid_argument("Provided index exceeds list length. Use push_back().\n"); + throw std::invalid_argument("linked list out of range. Use push_back() instead.\n"); } + // Set pointer node node* currentNode = head; + + // Travel to desired index unsigned int counter = 0; while (counter < idx - 1) { currentNode = currentNode->get_next(); ++counter; } + + // Save tyhe next node node* nextAfter = currentNode->get_next(); + // Insert node currentNode->set_next(nd); + // Re-link list nd->set_next(nextAfter); - ++len; - - return nd; + return currentNode; } -template +template node* sl_list::insert_node(const T dt, unsigned int idx) { - if (idx == 0) { - this->push_front(dt); - return head; - } - - else if (idx >= this->size()) { - throw std::invalid_argument("Provided index exceeds list length. Use push_back().\n"); - } - - node* currentNode = head; - unsigned int counter = 0; - while (counter < idx - 1) { - currentNode = currentNode->get_next(); - ++counter; - } - - currentNode->set_next(new node(currentNode->get_next(), dt)); - ++len; - - return currentNode->get_next(); + return insert_node(new node(dt), idx); } -template +template node* sl_list::get_head() const { return head; } -template +template void sl_list::set_head(node* const nd) { - head = nd; + pop_front(); + push_front(nd); } -template +template void sl_list::set_head(T dt) { - this->pop_front(); - this->push_front(dt); -} - -template -node* sl_list::get_tail() const { - return tail; -} - -template -void sl_list::set_tail(node* const nd) { - this->pop_back(); - this->push_back(nd); -} - -template -void sl_list::set_tail(T dt) { - this->pop_back(); - this->push_back(dt); + head->set_data(dt); } #endif // SINGLY_LINKED_LIST_H \ No newline at end of file