Kylin/DataStructure/CircularDoublyLinkedList.h
2023-12-27 10:29:16 +08:00

142 lines
4.6 KiB
C++

#ifndef DUALCIRCULARLIST_H
#define DUALCIRCULARLIST_H
#include "DoublyLinkedList.h"
namespace Kylin {
template <typename T>
class CircularDoublyLinkedList : public DoublyLinkedList<T> {
using Node = typename DoublyLinkedList<T>::Node;
using Iterator = typename DoublyLinkedList<T>::Iterator;
public:
static constexpr size_t npos = static_cast<size_t>(-1);
CircularDoublyLinkedList() {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
}
CircularDoublyLinkedList(std::initializer_list<T> init) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
for (auto &value : init) append(value);
}
CircularDoublyLinkedList(const CircularDoublyLinkedList &other) {
this->m_header.next = reinterpret_cast<Node *>(&(this->m_header));
this->m_header.prev = reinterpret_cast<Node *>(&(this->m_header));
this->m_last = reinterpret_cast<Node *>(&this->m_header);
auto sourceNode = other.m_header.next;
auto targetNode = reinterpret_cast<Node *>(&this->m_header);
for (size_t i = 0; i < other.m_size; i++) {
auto newNode = this->create();
if (newNode == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
newNode->value = sourceNode->value;
newNode->prev = targetNode;
newNode->next = targetNode->next;
targetNode->next = newNode;
targetNode = newNode;
sourceNode = sourceNode->next;
this->m_size++;
this->m_last = targetNode;
}
}
CircularDoublyLinkedList(CircularDoublyLinkedList &&other) {
this->m_size = other.m_size;
this->m_header = other.m_header;
this->m_last = other.m_last;
other.m_size = 0;
other.m_header.next = nullptr;
other.m_last = reinterpret_cast<Node *>(&other.m_header);
}
void insert(size_t index, const T &value) override {
index = index % (this->m_size + 1);
if (index == this->m_size) return append(value);
auto node = this->create();
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No momery to insert new element...");
node->value = value;
auto prev = position(index);
auto next = prev->next;
node->next = next;
node->prev = prev;
prev->next = node;
next->prev = node;
this->m_size++;
}
inline void append(const T &value) {
auto node = this->create();
if (node == nullptr) THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create node ...");
node->value = value;
node->prev = this->m_last;
node->next = this->m_last->next;
this->m_last->next->prev = node;
this->m_last->next = node;
this->m_last = node;
this->m_size++;
}
void removeAt(size_t index) override {
index = mod(index);
auto prev = position(index);
auto toDel = prev->next;
auto next = toDel->next;
prev->next = next;
next->prev = prev;
this->destroy(toDel);
this->m_size--;
}
T &last() override {
if (this->m_size <= 0) THROW_EXCEPTION(InvalidOperationException, "There is no element in the container.");
return this->m_header.prev->value;
}
void clear() override {
while (this->m_size > 0) {
removeAt(0);
}
}
Iterator end() override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
Iterator end() const override { return Iterator(reinterpret_cast<Node *>(&this->m_header)); }
~CircularDoublyLinkedList() { clear(); }
T &operator[](size_t index) override {
index = mod(index);
return position(index)->next->value;
}
protected:
size_t mod(size_t index) const { return (this->m_size == 0) ? 0 : (index % this->m_size); }
Node *position(size_t index) const override {
auto node = reinterpret_cast<Node *>(&(this->m_header));
for (size_t i = 0; i < index; i++) {
node = node->next;
}
return node;
}
};
} // namespace Kylin
#endif // DUALCIRCULARLIST_H