mirror of
https://hub.njuu.cf/TheAlgorithms/C-Plus-Plus.git
synced 2023-10-11 13:05:55 +08:00
fix: Circular linked list (#1825)
* Create reverse_binary_tree.cpp * Added documentation Added Documentation for the level_order_traversal() function, and implemented a print() function to display the tree to STDOUT * Added documentation * Renamed tests to test * Fixed issue with incorrect using statement * updating DIRECTORY.md * clang-format and clang-tidy fixes forfb86292d
* Added Test cases * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update operations_on_datastructures/reverse_binary_tree.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Changed int to int64_t * Updated documentation wording * Rewrote node struct and file structure * Added Circular Linked List * Update doc * Wrote bulk of code, added documentation * clang-format and clang-tidy fixes for06f11f1e
* Update operations_on_datastructures/circular_linked_list.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * Update operations_on_datastructures/circular_linked_list.cpp Co-authored-by: David Leal <halfpacho@gmail.com> * clang-format and clang-tidy fixes for25ed3ea0
* Added parameter documentation * Added destructor for CircularLinkedList * Fixed memory bug * Update circular_linked_list.cpp * Update circular_linked_list.cpp * Added move constructor and assignment operator * clang-format and clang-tidy fixes forb36e4736
* Fixed copy and move operators/constructors and added documentation * clang-format and clang-tidy fixes for24d3b9c2
* Added missing returns Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: David Leal <halfpacho@gmail.com> Co-authored-by: Abhinn Mishra <49574460+mishraabhinn@users.noreply.github.com>
This commit is contained in:
parent
b4b0864da1
commit
1f0eff28d0
@ -1,97 +1,348 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation for a [Circular Linked
|
||||
* List](https://www.geeksforgeeks.org/circular-linked-list/).
|
||||
* @details A Circular Linked List is a variation on the regular linked list, in
|
||||
* which the last node has a pointer to the first node, which creates a full
|
||||
* circle. Consequently, this allows any node to be used as the starting point
|
||||
* for the list.
|
||||
* @author [Alvin](https://github.com/polarvoid)
|
||||
*/
|
||||
|
||||
struct node {
|
||||
int val;
|
||||
node *next;
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace operations_on_datastructures
|
||||
* @brief Operations on Data Structures
|
||||
*/
|
||||
namespace operations_on_datastructures {
|
||||
|
||||
/**
|
||||
* @namespace circular_linked_list
|
||||
* @brief Functions for the [Circular Linked
|
||||
* List](https://www.geeksforgeeks.org/circular-linked-list/) implementation
|
||||
*/
|
||||
namespace circular_linked_list {
|
||||
|
||||
/**
|
||||
* @brief A Node struct that represents a single Node in a Binary Tree
|
||||
*/
|
||||
struct Node {
|
||||
int64_t data; ///< The value of the Node
|
||||
Node* next; ///< The Node's successor
|
||||
/**
|
||||
* @brief Creates a new Node with some initial data
|
||||
* @param _data Value of Node
|
||||
*/
|
||||
explicit Node(int64_t _data) {
|
||||
data = _data; ///< Set value of Node data
|
||||
next = nullptr; ///< Initialize successor
|
||||
}
|
||||
/**
|
||||
* @brief Creates a new Node with initial data and a successor
|
||||
* @param _data Value of Node
|
||||
* @param _next Pointer to the next Node
|
||||
*/
|
||||
explicit Node(int64_t _data, Node* _next) {
|
||||
data = _data; ///< Set value of Node data
|
||||
next = _next; ///< Initialize successor
|
||||
}
|
||||
};
|
||||
|
||||
node *start;
|
||||
/**
|
||||
* @brief A class that implements a Circular Linked List.
|
||||
*/
|
||||
class CircularLinkedList {
|
||||
private:
|
||||
Node* root; ///< Pointer to the root Node
|
||||
Node* end{}; ///< Pointer to the last Node
|
||||
|
||||
void insert(int x) {
|
||||
node *t = start;
|
||||
|
||||
if (start != NULL) {
|
||||
while (t->next != start) {
|
||||
t = t->next;
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an empty CircularLinkedList.
|
||||
*/
|
||||
CircularLinkedList() {
|
||||
root = nullptr;
|
||||
end = nullptr;
|
||||
}
|
||||
/**
|
||||
* @brief Copy constructor for CircularLinkedList.
|
||||
*/
|
||||
CircularLinkedList(const CircularLinkedList& copy) {
|
||||
erase();
|
||||
root = nullptr;
|
||||
Node* node = copy.root;
|
||||
while (node != nullptr) {
|
||||
insert(node->data);
|
||||
node = node->next;
|
||||
}
|
||||
node *n = new node;
|
||||
t->next = n;
|
||||
n->val = x;
|
||||
n->next = start;
|
||||
} else {
|
||||
node *n = new node;
|
||||
n->val = x;
|
||||
start = n;
|
||||
n->next = start;
|
||||
}
|
||||
}
|
||||
|
||||
void remove(int x) {
|
||||
node *t = start;
|
||||
node *p;
|
||||
while (t->val != x) {
|
||||
p = t;
|
||||
t = t->next;
|
||||
/**
|
||||
* @brief Move constructor for CircularLinkedList
|
||||
* @param source rvalue reference to a Circular Linked List
|
||||
*/
|
||||
CircularLinkedList(CircularLinkedList&& source) noexcept {
|
||||
root = source.root;
|
||||
end = source.end;
|
||||
source.root = nullptr;
|
||||
source.end = nullptr;
|
||||
}
|
||||
p->next = t->next;
|
||||
delete t;
|
||||
}
|
||||
|
||||
void search(int x) {
|
||||
node *t = start;
|
||||
int found = 0;
|
||||
while (t->next != start) {
|
||||
if (t->val == x) {
|
||||
cout << "\nFound";
|
||||
found = 1;
|
||||
break;
|
||||
/**
|
||||
* @brief Copy assignment operator
|
||||
* @param other Reference to a Circular Linked List
|
||||
* @returns Reference to CircularLinkedList
|
||||
*/
|
||||
CircularLinkedList& operator=(const CircularLinkedList& other) {
|
||||
erase();
|
||||
root = nullptr;
|
||||
Node* node = other.root;
|
||||
while (node != nullptr) {
|
||||
insert(node->data);
|
||||
node = node->next;
|
||||
}
|
||||
t = t->next;
|
||||
return *this;
|
||||
}
|
||||
if (found == 0) {
|
||||
cout << "\nNot Found";
|
||||
/**
|
||||
* @brief Move assignment operator
|
||||
* @param other rvalue reference to a Circular Linked List
|
||||
* @returns Reference to CircularLinkedList
|
||||
*/
|
||||
CircularLinkedList& operator=(CircularLinkedList&& other) noexcept {
|
||||
root = other.root;
|
||||
end = other.end;
|
||||
other.root = nullptr;
|
||||
other.end = nullptr;
|
||||
return *this;
|
||||
}
|
||||
/**
|
||||
* @brief Cleans up memory when destroyed
|
||||
*/
|
||||
~CircularLinkedList() { erase(); }
|
||||
/**
|
||||
* Iteratively frees each node in the Circular Linked List from the heap
|
||||
*/
|
||||
void erase() {
|
||||
if (root == nullptr) {
|
||||
return;
|
||||
}
|
||||
Node* node = root;
|
||||
do {
|
||||
Node* temp = node;
|
||||
node = node->next;
|
||||
delete (temp);
|
||||
} while (node != root);
|
||||
root = nullptr;
|
||||
end = nullptr;
|
||||
}
|
||||
/**
|
||||
* @brief Inserts all the values from a vector into the Circular Linked List
|
||||
* @details Goes through each element in the vector sequentially, inserting
|
||||
* it into the list
|
||||
* @param values The vector of integer values that is to be inserted
|
||||
* @returns void
|
||||
*/
|
||||
void insert(const std::vector<int64_t>& values) {
|
||||
for (int64_t value : values) {
|
||||
insert(value);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Inserts a single value into the Circular Linked List
|
||||
* @details Creates a Node with the given value, pointing to the root Node
|
||||
* and inserts it into the list
|
||||
* @param data The integer valus to be inserted
|
||||
* @returns void
|
||||
*/
|
||||
void insert(int64_t data) {
|
||||
Node* node = new Node(data, root);
|
||||
insert(node);
|
||||
}
|
||||
/**
|
||||
* @brief Inserts a given Node into the Circular Linked List
|
||||
* @details Checks wheter the list is empty, and inserts the Node, modifying
|
||||
* the end pointer
|
||||
* @param node The Node that is to be inserted
|
||||
* @returns void
|
||||
*/
|
||||
void insert(Node* node) {
|
||||
if (root == nullptr) {
|
||||
root = node; ///< Set node as the root
|
||||
node->next = root; ///< Point node to itself
|
||||
end = root; ///< Set the end to the root
|
||||
} else {
|
||||
end->next = node; ///< Append node to the end
|
||||
node->next = root; ///< Set the next value to the root
|
||||
end = node; ///< Make end point to node
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Prints the values of the Circular Linked List, beginning from the
|
||||
* root Node
|
||||
* @details Goes through each Node from the root and prints them out in
|
||||
* order
|
||||
* @returns void
|
||||
*/
|
||||
void print() { print(root); }
|
||||
/**
|
||||
* @brief Prints the values of the Circular Linked List, beginning from a
|
||||
* given Node to be used as the root
|
||||
* @details Goes through each Node from the given Node and prints them out
|
||||
* in order. If the list is empty, it prints the message 'Empty List!'
|
||||
* @param root The Node to start at
|
||||
* @returns void
|
||||
*/
|
||||
void print(Node* root) {
|
||||
Node* temp = root;
|
||||
if (root == nullptr) {
|
||||
std::cout << "Empty List!\n";
|
||||
return;
|
||||
}
|
||||
do {
|
||||
std::cout << temp->data << " ";
|
||||
temp = temp->next;
|
||||
} while (temp != root);
|
||||
std::cout << "\n";
|
||||
}
|
||||
/**
|
||||
* @brief Returns a std::vector of the values of the Circular Linked List
|
||||
* @details Starting from the root Node, appends each value of the list to a
|
||||
* std::vector and returns it
|
||||
* @returns A std::vector of the list's values
|
||||
*/
|
||||
std::vector<int64_t> values() { return values(root); }
|
||||
/**
|
||||
* @brief Returns a std::vector of the values of the Circular Linked List,
|
||||
* beginning from a given Node
|
||||
* @details Starting from a given Node, appends each value of the list to a
|
||||
* std::vector and returns it
|
||||
* @param root The Node to start at
|
||||
* @returns A std::vector of the list's values
|
||||
*/
|
||||
std::vector<int64_t> values(Node* root) {
|
||||
std::vector<int64_t> res;
|
||||
if (root == nullptr) {
|
||||
return res; ///< Return empty vector
|
||||
}
|
||||
Node* temp = root;
|
||||
do {
|
||||
res.push_back(temp->data);
|
||||
temp = temp->next;
|
||||
} while (temp != root);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace circular_linked_list
|
||||
|
||||
} // namespace operations_on_datastructures
|
||||
|
||||
/**
|
||||
* @namespace tests
|
||||
* @brief Testcases to check Circular Linked List.
|
||||
*/
|
||||
namespace tests {
|
||||
using operations_on_datastructures::circular_linked_list::CircularLinkedList;
|
||||
using operations_on_datastructures::circular_linked_list::Node;
|
||||
/**
|
||||
* @brief A Test to check a single value
|
||||
* @returns void
|
||||
*/
|
||||
void test1() {
|
||||
std::cout << "TEST CASE 1\n";
|
||||
std::cout << "Intialized a = {2}\n";
|
||||
std::cout << "Expected result: {2}\n";
|
||||
CircularLinkedList a;
|
||||
std::vector<int64_t> res = {2};
|
||||
a.insert(2);
|
||||
assert(a.values() == res);
|
||||
a.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
/**
|
||||
* @brief A Test to check a few values
|
||||
* @returns void
|
||||
*/
|
||||
void test2() {
|
||||
std::cout << "TEST CASE 2\n";
|
||||
std::cout << "Intialized a = {2, 5, 6}\n";
|
||||
std::cout << "Expected result: {2, 5, 6}\n";
|
||||
CircularLinkedList a;
|
||||
std::vector<int64_t> res = {2, 5, 6};
|
||||
a.insert(2);
|
||||
a.insert(5);
|
||||
a.insert(6);
|
||||
assert(a.values() == res);
|
||||
a.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
/**
|
||||
* @brief A Test to check an input array
|
||||
* @returns void
|
||||
*/
|
||||
void test3() {
|
||||
std::cout << "TEST CASE 3\n";
|
||||
std::cout << "Intialized a = {2, 7, 8, 3, 2, 6}\n";
|
||||
std::cout << "Expected result: {2, 7, 8, 3, 2, 6}\n";
|
||||
CircularLinkedList a;
|
||||
std::vector<int64_t> res = {2, 7, 8, 3, 2, 6};
|
||||
a.insert({2, 7, 8, 3, 2, 6});
|
||||
a.print();
|
||||
assert(a.values() == res);
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
/**
|
||||
* @brief A Test to check using a specific Node as the starting point
|
||||
* @returns void
|
||||
*/
|
||||
void test4() {
|
||||
std::cout << "TEST CASE 4\n";
|
||||
std::cout << "Intialized a = {2, 5}\n";
|
||||
std::cout << "Expected result: {5, 2}\n";
|
||||
CircularLinkedList a;
|
||||
std::vector<int64_t> res = {5, 2};
|
||||
a.insert(2);
|
||||
Node* start = new Node(5); ///< Node we will start printing from
|
||||
a.insert(start);
|
||||
assert(a.values(start) == res);
|
||||
a.print(start);
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
|
||||
void show() {
|
||||
node *t = start;
|
||||
do {
|
||||
cout << t->val << "\t";
|
||||
t = t->next;
|
||||
} while (t != start);
|
||||
/**
|
||||
* @brief A Test to check an empty list
|
||||
* @returns void
|
||||
*/
|
||||
void test5() {
|
||||
std::cout << "TEST CASE 5\n";
|
||||
std::cout << "Intialized a = {}\n";
|
||||
std::cout << "Expected result: Empty List!\n";
|
||||
CircularLinkedList a;
|
||||
std::vector<int64_t> res = {};
|
||||
assert(a.values() == res);
|
||||
a.print();
|
||||
std::cout << "TEST PASSED!\n\n";
|
||||
}
|
||||
} // namespace tests
|
||||
|
||||
/**
|
||||
* @brief Function to test the correctness of the Circular Linked List
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
tests::test1();
|
||||
tests::test2();
|
||||
tests::test3();
|
||||
tests::test4();
|
||||
tests::test5();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
int choice, x;
|
||||
do {
|
||||
cout << "\n1. Insert";
|
||||
cout << "\n2. Delete";
|
||||
cout << "\n3. Search";
|
||||
cout << "\n4. Print";
|
||||
cout << "\n\nEnter you choice : ";
|
||||
cin >> choice;
|
||||
switch (choice) {
|
||||
case 1:
|
||||
cout << "\nEnter the element to be inserted : ";
|
||||
cin >> x;
|
||||
insert(x);
|
||||
break;
|
||||
case 2:
|
||||
cout << "\nEnter the element to be removed : ";
|
||||
cin >> x;
|
||||
remove(x);
|
||||
break;
|
||||
case 3:
|
||||
cout << "\nEnter the element to be searched : ";
|
||||
cin >> x;
|
||||
search(x);
|
||||
break;
|
||||
case 4:
|
||||
show();
|
||||
break;
|
||||
}
|
||||
} while (choice != 0);
|
||||
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user