#include "doubly-linked-list.h" using namespace seq; // return the size (number of items in the doubly linked list) size_t DoublyLinkedList::size() const { size_t count = 0; for(DoublyLinkedListNode* n = this->head; n != nullptr; n = n->get_next()) count++; return count; } // return pointer to the node at position i, counting from 0 // for negative numbers, count from the tail (-1) backward (-2, -3, ...) DoublyLinkedListNode* DoublyLinkedList::index(int i) const { DoublyLinkedListNode* n = this->head; if(i > 0) { for(int k = 0; k < i; k++) { assert(n != nullptr); n = n->get_next(); } } else /** in the doubly linked list, we can walk backward, so let us allow it for negative i **/ { DoublyLinkedListNode* n = this->tail; for(int k = -1; k > i; k--) { assert(n != nullptr); n = n->get_prev(); } } return n; } // add an item at the end of the list void DoublyLinkedList::push_back(const int& pushed_item) { DoublyLinkedListNode* new_node = new DoublyLinkedListNode; new_node->set_item(pushed_item); if(this->empty()) this->head = new_node; else { this->tail->set_next(new_node); new_node->set_prev(this->tail); /** attachment in the doubly linked list goes both ways **/ } this->tail = new_node; } // add an item at the beginning of the list void DoublyLinkedList::push_front(const int& pushed_item) { DoublyLinkedListNode* new_node = new DoublyLinkedListNode; new_node->set_item(pushed_item); if(this->empty()) this->tail = new_node; else { new_node->set_next(this->head); // FIX BUG from the previous version, which was "new_node->set_next(this->head->get_next());" this->head->set_prev(new_node); // FIX BUG from the previous version, which was "this->head->get_next()->set_prev(new_node);" } this->head = new_node; } // remove the head node and item void DoublyLinkedList::pop_front() { if(this->empty()) return; // nothing there to remove DoublyLinkedListNode* successor = this->head->get_next(); if(successor) successor->set_prev(nullptr); /** we must detach the previous head node from its successor **/ delete this->head; this->head = successor; // successor of the previous head is the new head if(this->head == nullptr) this->tail = nullptr; // catch special case: the list is now empty } // remove the tail node and item /** note how this is much easier for the doubly than for the singly linked list; ** ** we can simply take the "pop_front()" implementation and do everything symmetrically **/ void DoublyLinkedList::pop_back() { if(this->empty()) return; // nothing there to remove DoublyLinkedListNode* predecessor = this->tail->get_prev(); if(predecessor) predecessor->set_next(nullptr); delete this->tail; this->tail = predecessor; /** predecessor of the previous tail is the new tail **/ if(this->tail == nullptr) this->head = nullptr; /** catch special case: the list is now empty **/ } // insert an item at index i // for negative numbers, count from the tail (-1) backward (-2, -3, ...) void DoublyLinkedList::insert_at(int i, const int& inserted_item) { if(i == 0) { this->push_front(inserted_item); return; } else if(i == -1) { this->push_back(inserted_item); return; } DoublyLinkedListNode* predecessor = this->index(i-1); this->insert_successor_to(predecessor, inserted_item); } // remove the item at index i // for negative numbers, count from the tail (-1) backward (-2, -3, ...) void DoublyLinkedList::erase_at(int i) { if(i == 0) { this->pop_front(); return; } else if(i == -1) { this->pop_back(); return; } DoublyLinkedListNode* erased_node = this->index(i); this->erase_node(erased_node); } // insert an item after given node void DoublyLinkedList::insert_successor_to(DoublyLinkedListNode* predecessor, const int& inserted_item) { DoublyLinkedListNode* new_node = new DoublyLinkedListNode; new_node->set_item(inserted_item); DoublyLinkedListNode* successor = predecessor->get_next(); predecessor->set_next(new_node); new_node->set_prev(predecessor); /** attach both ways **/ new_node->set_next(successor); if(!successor) this->tail = new_node; else successor->set_prev(new_node); /** attach both ways **/ } /** remove "erased_node" from the doubly linked list **/ void DoublyLinkedList::erase_node(DoublyLinkedListNode* erased_node) { if(erased_node->get_prev() == nullptr) /** erase the head **/ { this->pop_front(); return; } if(erased_node->get_next() == nullptr) /** erase the tail **/ { this->pop_back(); return; } /** now attach predecessor and successor to each other **/ erased_node->get_prev()->set_next(erased_node->get_next()); erased_node->get_next()->set_prev(erased_node->get_prev()); delete erased_node; /** "erased_node" detached now, we can delete it **/ }