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 for fb86292d

* 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 for 06f11f1e

* 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 for 25ed3ea0

* 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 for b36e4736

* Fixed copy and move operators/constructors and added documentation

* clang-format and clang-tidy fixes for 24d3b9c2

* 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:
Alvin Philips 2021-11-02 22:33:49 +05:30 committed by GitHub
parent b4b0864da1
commit 1f0eff28d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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;
}
node *n = new node;
t->next = n;
n->val = x;
n->next = start;
/**
* @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;
}
}
/**
* @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 {
node *n = new node;
n->val = x;
start = n;
n->next = start;
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
}
}
void remove(int x) {
node *t = start;
node *p;
while (t->val != x) {
p = t;
t = t->next;
/**
* @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;
}
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;
}
t = t->next;
}
if (found == 0) {
cout << "\nNot Found";
}
}
void show() {
node *t = start;
do {
cout << t->val << "\t";
t = t->next;
} while (t != start);
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";
}
/**
* @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;
}