-
-
Notifications
You must be signed in to change notification settings - Fork 7.3k
/
Copy pathcircular_linked_list.cpp
348 lines (336 loc) · 9.88 KB
/
circular_linked_list.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/**
* @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)
*/
#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
}
};
/**
* @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
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;
}
}
/**
* @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 {
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";
}
/**
* @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() {
test(); // run self-test implementations
return 0;
}