#ifndef _SINGLY_LINKED_LIST_IMPL #define _SINGLY_LINKED_LIST_IMPL #include template class LinkedList { private: struct LinkedListNode { T data; LinkedListNode* next; LinkedListNode(const T& elem, LinkedListNode* n = nullptr) : data{ elem }, next { n } {} }; void free(); void copy(const LinkedList&); public: class Iterator { private: // Текущия възел в обхождането LinkedListNode* currentNode; Iterator(LinkedListNode* arg) : currentNode { arg } {} public: Iterator& operator++() { if(currentNode == nullptr) return *this; currentNode = currentNode->next; return *this; } Iterator operator++(int) { Iterator temp = *this; ++(*this); return temp; } T& operator*() { return currentNode->data; } bool operator==(const Iterator& other) const { return other.currentNode == currentNode; } bool operator!=(const Iterator& other) const { return !(*this == other); } friend class LinkedList; }; class ConstIterator { private: const LinkedListNode* currentNode; // Това вече е указател към константна памет! ConstIterator(LinkedListNode* arg) : currentNode { arg } {} public: ConstIterator& operator++() { if(currentNode == nullptr) return *this; currentNode = currentNode->next; return *this; } ConstIterator operator++(int) { ConstIterator temp = *this; ++(*this); return temp; } const T& operator*() const { return currentNode->data; } bool operator==(const ConstIterator& other) const { return other.currentNode == currentNode; } bool operator!=(const ConstIterator& other) const { return !(*this == other); } friend class LinkedList; }; LinkedList(); LinkedList(const LinkedList&); LinkedList(LinkedList&&); LinkedList& operator=(const LinkedList&); LinkedList& operator=(LinkedList&&); Iterator begin() { return Iterator(head); } Iterator end() { return Iterator(nullptr); } ConstIterator begin() const { return ConstIterator(head); } ConstIterator end() const { return ConstIterator(nullptr); } ConstIterator cbegin() const { return ConstIterator(head); } ConstIterator cend() const { return ConstIterator(nullptr); } void pushBack(const T&); void popBack(); void pushFront(const T&); void popFront(); const T& front() const; const T& back() const; T& front(); T& back(); bool empty() const; size_t size() const; ~LinkedList(); private: LinkedListNode* head; LinkedListNode* tail; size_t sizeOfList; }; template LinkedList::LinkedList() : head {nullptr}, tail {nullptr}, sizeOfList { 0 } {} template void LinkedList::free() { while(head) { LinkedListNode* toDelete = head; head = head->next; delete toDelete; } sizeOfList = 0; } template void LinkedList::copy(const LinkedList& other) { LinkedListNode* iter = other.head; while(iter) { pushBack(iter->data); iter = iter->next; } sizeOfList = other.sizeOfList; } template LinkedList::LinkedList(const LinkedList& other) : head {nullptr}, tail{ nullptr } { copy(other); } template LinkedList::LinkedList(LinkedList&& other) { head = other.head; tail = other.tail; sizeOfList = other.sizeOfList; other.head = other.tail = nullptr; other.sizeOfList = 0; } template LinkedList& LinkedList::operator=(const LinkedList& other) { if(this != & other) { free(); copy(other); } return *this; } template LinkedList& LinkedList::operator=(LinkedList&& other) { if(this != &other) { free(); head = other.head; tail = other.tail; sizeOfList = other.sizeOfList; other.head = other.tail = nullptr; other.sizeOfList = 0; } return *this; } template void LinkedList::pushBack(const T& elem) { LinkedListNode* toInsert = new LinkedListNode(elem); ++sizeOfList; if(empty()) { head = tail = toInsert; } else { tail->next = toInsert; tail = toInsert; } } template void LinkedList::popBack() { if(empty()) { throw std::runtime_error("Tried to pop back on empty list!"); } --sizeOfList; if(head == tail) { delete tail; head = tail = nullptr; } else { LinkedListNode* newTail = head; // O(n) за n дължината на свързания списък while (newTail->next != tail) { newTail = newTail->next; } delete tail; tail = newTail; tail->next = nullptr; } } template void LinkedList::pushFront(const T& elem) { LinkedListNode* toInsert = new LinkedListNode(elem, head); if(empty()) tail = toInsert; head = toInsert; ++sizeOfList; } template void LinkedList::popFront() { if(empty()) throw std::runtime_error("Cannot pop front from empty list!"); if(head == tail) { delete tail; head = tail = nullptr; } else { LinkedListNode* toDelete = head; head = head->next; delete toDelete; } --sizeOfList; } template bool LinkedList::empty() const { return head == nullptr; } template size_t LinkedList::size() const { return sizeOfList; } template const T& LinkedList::front() const { if(empty()) throw std::runtime_error("Empty list!"); return head->data; } template T& LinkedList::front() { if(empty()) throw std::runtime_error("Empty list!"); return head->data; } template const T& LinkedList::back() const { if(empty()) throw std::runtime_error("Empty list!"); return tail->data; } template T& LinkedList::back() { if(empty()) throw std::runtime_error("Empty list!"); return tail->data; } template LinkedList::~LinkedList() { free(); } #endif