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 {
|
#include <cassert> /// for assert
|
||||||
int val;
|
#include <iostream> /// for IO operations
|
||||||
node *next;
|
#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) {
|
public:
|
||||||
node *t = start;
|
/**
|
||||||
|
* @brief Creates an empty CircularLinkedList.
|
||||||
if (start != NULL) {
|
*/
|
||||||
while (t->next != start) {
|
CircularLinkedList() {
|
||||||
t = t->next;
|
root = nullptr;
|
||||||
|
end = nullptr;
|
||||||
}
|
}
|
||||||
node *n = new node;
|
/**
|
||||||
t->next = n;
|
* @brief Copy constructor for CircularLinkedList.
|
||||||
n->val = x;
|
*/
|
||||||
n->next = start;
|
CircularLinkedList(const CircularLinkedList& copy) {
|
||||||
|
erase();
|
||||||
|
root = nullptr;
|
||||||
|
Node* node = copy.root;
|
||||||
|
while (node != nullptr) {
|
||||||
|
insert(node->data);
|
||||||
|
node = node->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;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @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 {
|
} else {
|
||||||
node *n = new node;
|
end->next = node; ///< Append node to the end
|
||||||
n->val = x;
|
node->next = root; ///< Set the next value to the root
|
||||||
start = n;
|
end = node; ///< Make end point to node
|
||||||
n->next = start;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void remove(int x) {
|
|
||||||
node *t = start;
|
|
||||||
node *p;
|
|
||||||
while (t->val != x) {
|
|
||||||
p = t;
|
|
||||||
t = t->next;
|
|
||||||
}
|
}
|
||||||
p->next = t->next;
|
/**
|
||||||
delete t;
|
* @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
|
||||||
void search(int x) {
|
* order
|
||||||
node *t = start;
|
* @returns void
|
||||||
int found = 0;
|
*/
|
||||||
while (t->next != start) {
|
void print() { print(root); }
|
||||||
if (t->val == x) {
|
/**
|
||||||
cout << "\nFound";
|
* @brief Prints the values of the Circular Linked List, beginning from a
|
||||||
found = 1;
|
* given Node to be used as the root
|
||||||
break;
|
* @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;
|
||||||
}
|
}
|
||||||
t = t->next;
|
|
||||||
}
|
|
||||||
if (found == 0) {
|
|
||||||
cout << "\nNot Found";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void show() {
|
|
||||||
node *t = start;
|
|
||||||
do {
|
do {
|
||||||
cout << t->val << "\t";
|
std::cout << temp->data << " ";
|
||||||
t = t->next;
|
temp = temp->next;
|
||||||
} while (t != start);
|
} 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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 main() {
|
||||||
int choice, x;
|
test(); // run self-test implementations
|
||||||
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);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user