AlgoPlus v0.1.0
Loading...
Searching...
No Matches
frequency_list.h
1#ifndef FREQUENCY_LIST_H
2#define FREQUENCY_LIST_H
3
4#ifdef ENABLE_LINKED_LIST_VISUALIZATION
5#include "../../visualization/list_visual/linked_list_visualization.h"
6#endif
7
8#ifdef __cplusplus
9#include <cstdint>
10#include <iostream>
11#include <memory>
12#include <string>
13#include <vector>
14#endif
15
32template <typename T> class frequency_list {
33 public:
45 inline explicit frequency_list(std::vector<T> data = {}) noexcept
46 : head(nullptr), tail(nullptr) {
47 if (!data.empty()) {
48 for (const auto& item : data) {
49 this->push_back(item);
50 }
51 }
52 }
53
63 inline frequency_list(const frequency_list<T>& list) : head(nullptr), tail(nullptr), size(0) {
64 for (auto iter = list.head; iter != nullptr; iter = iter->next) {
65 this->push_back(iter->data);
66 }
67 }
68
69 class Iterator;
70
83 void push_back(T data);
84
94 void push_front(T data);
95
107 bool search(T key);
108
115 int64_t get_frequency(T key);
116
127 void erase(T key);
128
133
139 std::vector<std::pair<T, int64_t>> elements();
140
146 bool empty() { return head == nullptr; }
147
155 Iterator begin() { return Iterator(head); }
156
166 Iterator end() { return Iterator(nullptr); }
167
173 void visualize();
174
187 friend std::ostream& operator<<(std::ostream& os, const frequency_list<T>& flist) {
188 auto iterator = flist.head;
189 while (iterator != nullptr) {
190 os << iterator->data << "(" << iterator->freq << ") ";
191 iterator = iterator->next;
192 }
193 return os;
194 }
195
196 private:
197 struct node {
198 T data;
199 int64_t freq;
200 std::shared_ptr<node> next;
201 std::weak_ptr<node> prev;
202
203 node(T data, int64_t freq, std::weak_ptr<node> prev, std::shared_ptr<node> next)
204 : data(data), freq(freq), prev(prev), next(next) {}
205
206 void add_freq() { freq++; }
207 void reset_freq() { freq = 1; }
208 };
209
210 std::shared_ptr<node> head;
211 node* tail;
212 uint64_t size{0};
213
225 void update_list_sequence();
226
239 void swap_nodes(std::shared_ptr<node> a, std::shared_ptr<node> b);
240
247 std::string generate();
248};
249
250template <typename T>
251inline void frequency_list<T>::swap_nodes(std::shared_ptr<node> a, std::shared_ptr<node> b) {
252 if (a == nullptr || b == nullptr || a->next != b)
253 return;
254
255 // Attach b's next to a and a's prev to b
256 a->next = b->next;
257 b->prev = a->prev;
258
259 // If b's next exists, attach a to its prev
260 if (b->next)
261 b->next->prev = a;
262
263 // If a's prev exists(i.e., a is not the head), attach b to its next
264 if (a->prev.lock())
265 a->prev.lock()->next = b;
266
267 // Now, attach a to b's next and b to a's prev
268 b->next = a;
269 a->prev = b;
270
271 // If the node a was the head node, update the head to b
272 if (head == a)
273 head = b;
274}
275
276template <typename T> inline void frequency_list<T>::update_list_sequence() {
277 auto current_node = head;
278
279 while (current_node != nullptr && current_node->next != nullptr) {
280 if (current_node->freq < current_node->next->freq) {
281 swap_nodes(current_node, current_node->next);
282
283 if (current_node->prev.lock())
284 current_node = current_node->prev.lock();
285
286 } else
287 current_node = current_node->next;
288 }
289}
290
291template <typename T> inline void frequency_list<T>::reset_frequency() {
292 auto iterator = head;
293
294 while (iterator != nullptr) {
295 iterator->reset_freq();
296 iterator = iterator->next;
297 }
298}
299
300template <typename T> inline void frequency_list<T>::push_front(T data) {
301 auto Iterator = head;
302
303 // Iterating over the list to find if the same data is already present
304 while (Iterator != nullptr) {
305 if (Iterator->data == data) {
306 // if data is found, increase frequency and re-sort the list
307 Iterator->freq++;
308 update_list_sequence();
309 return;
310 }
311 Iterator = Iterator->next;
312 }
313
314 // if data is not found in the list, add new node at front
315 auto new_node = std::make_shared<node>(data, 1, std::weak_ptr<node>(), head);
316
317 if (head != nullptr) {
318 head->prev = new_node;
319 }
320
321 head = new_node;
322
323 size++;
324}
325
326template <typename T> inline void frequency_list<T>::erase(T key) {
327 auto iterator = head;
328
329 // special case: deleting the head node
330 if (head != nullptr && head->data == key) {
331 head = head->next;
332 if (head)
333 head->prev.reset();
334 size--;
335 return;
336 }
337
338 // iterate over the rest nodes
339 while (iterator != nullptr) {
340 if (iterator->data == key) {
341 // connect previous node and next node
342 if (auto sharedPrev = iterator->prev.lock()) {
343 sharedPrev->next = iterator->next;
344 }
345 if (iterator->next) {
346 iterator->next->prev = iterator->prev;
347 }
348 // deleting the node by falling out of scope
349 size--;
350 return;
351 }
352 iterator = iterator->next;
353 }
354}
355
356template <typename T> inline int64_t frequency_list<T>::get_frequency(T key) {
357 auto iterator = head;
358
359 while (iterator != nullptr) {
360 if (iterator->data == key) {
361 return iterator->freq;
362 }
363
364 iterator = iterator->next;
365 }
366
367 return -1;
368}
369
370template <typename T> inline bool frequency_list<T>::search(T key) {
371 auto iterator = head;
372
373 while (iterator != nullptr) {
374 if (iterator->data == key) {
375 iterator->add_freq();
376 update_list_sequence();
377 return true;
378 }
379
380 iterator = iterator->next;
381 }
382
383 return false;
384}
385
386template <typename T> inline void frequency_list<T>::push_back(T data) {
387 if (this->empty()) {
388 head = std::make_shared<node>(data, 1, std::weak_ptr<node>(), nullptr);
389 return;
390 }
391
392 auto iterator = head;
393 while (iterator) {
394 if (iterator->data == data) {
395 iterator->add_freq();
396 update_list_sequence();
397 return;
398 }
399 if (!iterator->next)
400 break;
401 iterator = iterator->next;
402 }
403
404 auto newNode = std::shared_ptr<node>(new node(data, 1, iterator, nullptr));
405 if (iterator)
406 iterator->next = newNode;
407 size++;
408}
409
410template <typename T> inline std::vector<std::pair<T, int64_t>> frequency_list<T>::elements() {
411 std::vector<std::pair<T, int64_t>> ans;
412 std::shared_ptr<node> root = head;
413 while (root) {
414 ans.push_back(std::make_pair(root->data, root->freq));
415 root = root->next;
416 }
417 return ans;
418}
419
420template <typename T> inline std::string frequency_list<T>::generate() {
421 std::string gen = "";
422 gen += "rankdir=LR;";
423 gen += '\n';
424 gen += "node [shape=record;]";
425 gen += '\n';
426 std::vector<std::pair<T, int64_t>> els = this->elements();
427 if (std::is_same_v<T, std::string> || std::is_same_v<T, char>) {
428 for (auto& x : els) {
429 gen += x.first;
430 gen += " [label=<{ ";
431 gen += x.first;
432 gen += " | ";
433 gen += x.second;
434 gen += " | }>] ;";
435 gen += '\n';
436 }
437
438 std::shared_ptr<node> curr = head;
439 while (curr->next) {
440 gen += curr->data;
441 gen += ":ref -> ";
442 gen += curr->next->data;
443 gen += ":data [arrowhead=vee, arrowtail=dot, dir=both];";
444 gen += '\n';
445
446 gen += curr->next->data;
447 gen += ":data -> ";
448 gen += curr->data;
449 gen += ":ref [arrowhead=vee, arrowtail=dot, dir=both];";
450 gen += '\n';
451
452 curr = curr->next;
453 }
454 } else {
455 for (auto& x : els) {
456 std::cout << std::to_string(x.first) << " " << std::to_string(x.second) << '\n';
457 gen += std::to_string(x.first);
458 gen += " [label=<{ ";
459 gen += std::to_string(x.first);
460 gen += " | ";
461 gen += std::to_string(x.second);
462 gen += " | }>] ;";
463 gen += '\n';
464 }
465
466 std::shared_ptr<node> curr = head;
467 while (curr->next) {
468 gen += std::to_string(curr->data);
469 gen += ":ref -> ";
470 gen += std::to_string(curr->next->data);
471 gen += ":data [arrowhead=vee, arrowtail=dot, dir=both];";
472 gen += '\n';
473
474 gen += std::to_string(curr->next->data);
475 gen += ":data -> ";
476 gen += std::to_string(curr->data);
477 gen += ":ref [arrowhead=vee, arrowtail=dot, dir=both];";
478 gen += '\n';
479
480 curr = curr->next;
481 }
482 }
483 return gen;
484}
485
486#ifdef ENABLE_LINKED_LIST_VISUALIZATION
487template <typename T> inline void frequency_list<T>::visualize() {
488 std::string generated = this->generate();
489 linked_list_visualization::visualize(generated);
490}
491#endif
492
493template <typename T> class frequency_list<T>::Iterator {
494 private:
495 std::shared_ptr<node> current;
496
497 public:
503 explicit Iterator(const std::shared_ptr<node>& ptr) noexcept : current(ptr) {}
504
514 Iterator& operator=(const std::shared_ptr<node>& ptr) {
515 current = ptr;
516 return *this;
517 }
518
529 if (current) {
530 current = current->next;
531 }
532 return *this;
533 }
534
545 Iterator tmp = *(this);
546 ++*(this);
547 return tmp;
548 }
549
560 if (current) {
561 current = current->prev;
562 }
563 return *(this);
564 }
565
575 Iterator tmp = *(this);
576 --*(this);
577 return tmp;
578 }
579
589 bool operator==(const Iterator& it) { return it.current == this->current; }
590
600 bool operator!=(const Iterator& it) { return it.current != this->current; }
601
607 T operator*() { return current->data; }
608};
609
610#endif // FREQUENCY_LIST_H
Definition frequency_list.h:493
T operator*()
Dereference operator for the Iterator class.
Definition frequency_list.h:607
Iterator & operator=(const std::shared_ptr< node > &ptr)
Assignment operator for the Iterator class.
Definition frequency_list.h:514
Iterator & operator++()
Pre-increment operator for the Iterator class.
Definition frequency_list.h:528
Iterator(const std::shared_ptr< node > &ptr) noexcept
Iterator class for a linked list.
Definition frequency_list.h:503
Iterator operator++(int)
Post-increment operator for the Iterator class.
Definition frequency_list.h:544
bool operator==(const Iterator &it)
Equality operator for the Iterator class.
Definition frequency_list.h:589
Iterator operator--(int)
Post-increment –operator for the Iterator class. This operator overloads the post-increment operator ...
Definition frequency_list.h:574
Iterator & operator--()
Pre-increment – operator for the Iterator class. This operator overloads the pre-increment operator (...
Definition frequency_list.h:559
bool operator!=(const Iterator &it)
Inequality operator for the Iterator class.
Definition frequency_list.h:600
bool empty()
Checks if the frequency list is empty.
Definition frequency_list.h:146
void push_front(T data)
Adds an element to the front of the frequency list.
Definition frequency_list.h:300
void erase(T key)
Removes the first occurrence of a given key in the frequency list.
Definition frequency_list.h:326
int64_t get_frequency(T key)
Gets the frequency of a key in the frequency list.
Definition frequency_list.h:356
Iterator begin()
Get an iterator pointing to the beginning of the frequency list.
Definition frequency_list.h:155
friend std::ostream & operator<<(std::ostream &os, const frequency_list< T > &flist)
Overloaded output stream insertion operator for the frequency_list class.
Definition frequency_list.h:187
bool search(T key)
Searches for a given key in the frequency list.
Definition frequency_list.h:370
std::vector< std::pair< T, int64_t > > elements()
Returns all the elements of the list.
Definition frequency_list.h:410
void reset_frequency()
Resets the frequency of all nodes in the frequency list to 1.
Definition frequency_list.h:291
Iterator end()
Get an iterator pointing to the end of the frequency list.
Definition frequency_list.h:166
frequency_list(const frequency_list< T > &list)
Copy constructor for the frequency_list class.
Definition frequency_list.h:63
void push_back(T data)
Adds an element to the back of the frequency list.
Definition frequency_list.h:386
void visualize()
visualize function for frequency_list Class returns a .dot file that can be previewd with graphviz pl...
frequency_list(std::vector< T > data={}) noexcept
Constructs a frequency_list object with an optional initializer list of elements.
Definition frequency_list.h:45