170 likes | 236 Views
A Doubly Linked List. prev. data. next. header. There’s the need to access a list in reverse order. dnode. Doubly Linked List Implementation. template < typename T> class dnode { public : // the members of a dnode object are used for operations within a
E N D
A Doubly Linked List prev data next header There’s the need to access a list in reverse order dnode
Doubly Linked List Implementation template <typename T> class dnode { public: // the members of a dnode object are used for operations within a // doubly linked list; access is simplified by making them public T nodeValue; // data value of the node dnode<T> *prev; // previous node in the list dnode<T> *next; // next node in the list // default constructor. creates object with value T(), the default value // of type T. set the node pointers to point at the node itself dnode(); // constructor with an argument to initialize nodeValue. // set the node pointers to point at the node itself dnode(const T& value): nodeValue(value); };
Default and Copy Constructors Constructor creates an empty list by assigning this to both left and right. template <typename T> dnode<T>::dnode() { next = this; // the next node is the current node prev = this; // the previous node is the current node } template <typename T> dnode<T>::dnode(const T& value): nodeValue(value) { next = this; // the next node is the current node prev = this; // the previous node is the current node }
Node Insertion prev prev prev next next current node prevNode newNode dnode<T> *newNode, *prevNode; // allocate a new node and assign prevNode to reference the predecessor of curr newNode = new dnode<T>(item); prevNode = curr->prev; // update pointer fields in newNode newNode->prev = prevNode; newNode->next = curr; // update curr and its predecessor to point to newNode prevNode->next = newNode; curr->prev = newNode;
The insert() Function template <typename T> dnode<T> *insert(dnode<T> *curr, const T& item) { // declare pointer variables for the new node and the previous node dnode<T> *newNode, *prevNode; // allocate new dnode with item as initial value newNode = new dnode<T>(item); // assign prevNode the pointer value of node before p prevNode = curr->prev; // update pointer fields in newNode newNode->prev = prevNode; newNode->next = curr; // update curr and prevNode to point at newNode prevNode->next = newNode; curr->prev = newNode; return newNode; }
Node Deletion – Self Removal prev next curr prevNode succNode prev next prev next dnode<T> *prevNode = curr->prev, *succNode = curr->next; prevNode -> next = succNode; succNode -> prev = prevNode; delete curr;
The erase() Function template <typename T> void erase(dnode<T> *curr) { // return if the list is empty if (curr->next == curr) return; // declare pointers for the predecessor and successor nodes dnode<T> *prevNode = curr->prev, *succNode = curr->next; // update pointer fields for predecessor and successor prevNode->next = succNode; succNode->prev = prevNode; // deallocate the memory used by the node delete curr; }
Circular Doubly Linked Lists next header Avoid tests to determine if the list is empty. Remove the additional code for updating the head pointer. header Simplify coding. prev An empty circular linked list header -> next == header header-> prev == header
Scanning a Doubly Linked List template <typename T> void writeDlinkedList(dnode<T>* header, const string& separator = “ “) { // header points at first dnode. p moves through the list dnode<T> *p = header->next; while (p != header) { cout << p->nodeValue << separator; p = p->next; } }
The miniList Class A variation of the STL list class. A doubly linked list as the underlying structure. Implementation of an iterator. Private members: dnode<T> *header; int listSize; dnode<T> *getDNode(const T& item); // allocate a dnode dnode<T> *dinsert(dnode<T> *curr, const T& item); // insert before node curr and // return address of the new node void derase(dnode<T> *curr); // erase node curr from the linked list
A Constructor template <typename T> miniList<T>::miniList(int n, const T& value): listSize(n) { int i; // create an empty list header = new dnode<T>; if (header == NULL) throw memoryAllocationError (“miniList(): memory allocation failure”); // insert n copies of value at the front of the list for (i = 0; i < n; i++) dinsert(header->next, value); }
Copy Constructor template <typename T> miniList<T>::miniList(const miniList<T>& obj): listSize(obj.listSize) { // curr moves through the nodes in obj, and end marks the finish // of a traversal through obj dnode<T> *curr = obj.header->next, *end = obj.header; // create an empty list header = new dnode<T>; if (header == NULL) throw memoryAllocationError (“miniList(): memory allocation failure”); // insert the values in the linked list obj.header at the back of the current list while (curr != end) { dinsert(header, curr->nodeValue); // before the header, i.e., back of the list curr = curr -> next; } }
Iterator Nested Class class iterator { public: friend class miniList<T>; // needed by the const_iterator constructor // that converts a const iterator to a const_iterator friend class const_iterator; // constructor iterator() {} bool operator==(const iterator& rhs) const; bool operator!= (const iterator& rhs) const; T& operator* (); // pointer dereference operator iterator& operator++ (); iterator operator++ (int) ; // postfix increment. move forward onenode iterator& operator-- (); iterator operator-- (int); private: dnode<T> *nodePtr; // pointer to the current list node // private constructor. converts p to an iterator // by assigning p to nodePtr iterator(dnode<T> *p): nodePtr(p) {} }; template <typename T> class miniList { public: // include the iterator // nested classes #include “d_liter.h” … private: dnode<T> *header; int listSize; dnode<T> *getDNode( const T& item); dnode<T> *dinsert( dnode<T> *curr, const T& item); void derase(dnode<T> *curr); };
Implementing Iterator Operations T& operator* () { // if the node's successor is itself, the list is empty if (nodePtr->next == nodePtr) throw referenceError("miniList iterator: reference error"); return nodePtr->nodeValue; } iterator& operator++ () { nodePtr = nodePtr->next; // move to the successor of nodePtr return *this; // return new iterator value } iterator operator++ (int) { // save the current value of the iterator iterator tmp = *this; // move to the successor of nodePtr nodePtr = nodePtr->next; return tmp; // return original iterator value }
begin() and insert() Both are member functions of class miniList. template <typename T> miniList<T>::iterator miniList<T>::begin() { return iterator(header->next); } template <typename T> miniList<T>::iterator miniList<T>::insert(iterator pos, const T& item) { dnode<T> *curr = pos.nodePtr, *newNode; // insert item before curr and capture the new node’s address newNode = dinsert(curr, item); // increment the list size listSize++; // constructor converts newNode to an iterator return iterator(newNode); }