Doubly-Linked Lists 4-02-2013
Doubly-linked list Implementation of List ListIterator Reading: Maciel, Chapter 13 HW#4 due: Wednesday, 4/03 (new ew due e dat ate) e) Quiz on Thursday, 4/04, on nodes & pointers Review Session on pointers – tonight, Tuesday, 4/02, 7:00 to 8:00 in the ITL Exam#2: Wednesday, April 10 th , 7:00 pm, Science Center 162
Limitations of a singly-linked list include: can insert only after a referenced node removing node requires pointer to previous node can traverse list only in the forward direction We can remove these limitations: Add a pointer in each node to the previous node: This is called a doub ubly-linked inked list st
DNode ode* * sharon haron = new new DNod Node("Sha Sharon") ron"); // Li Link nk new new DNod Node to its o its ne neigh ighbors bors sharo aron->next next = = sam am; // S // Step tep 1 1 sharo aron->prev prev = = sam am->prev rev; / ; // S / Step 2 tep 2
// Link old predecessor of sam to new predecessor. sam->prev->next = sharon; // Step 3 // Link to new predecessor. sam->prev = sharon; // Step 4
harry->prev->next = harry->next; // Step 1 harry->next->prev = harry->prev; // Step 2 delete harry;
represent a list with three data members: head of the list tail of the list current size of the list represent contents with DNodes another simplification: add a dummy first node
// // dnode.h de.h #ifndef DNODE_H_ #define DNODE_H_ /** A DNode ode is the building ding block ck for a d double ble-linked linked list. . */ */ struct DNode { T data; DNode* next; // pointer to next DNode DNode* prev; // pointer to previous DNode DNode(const T& data_item, DNode* prev_val = NULL DNode* next_val = NULL) : data(data_item), next(next_ptr), prev(prev_val) {} }; #endif
template<typename T> // // cf cf list. t.h class List { public: lic: #i #incl clude ude "list_i t_itera terator.h tor.h" " // Give ve list ac acce cess ss to inter ernal nal val alues ues in iter erat ator. or. friend nd cl class s iterator; ator; #i #incl clude ude "list_const_i t_const_itera terator.h tor.h" // Give ve list acc ccess ss to internal rnal values lues in co const_i st_iter terator ator. friend end cl clas ass s co const_ite st_iterator rator; priva ivate: te: // Inse sert rt definiti nition on of neste ted d cl class s DNode de here. #include “ DNode Node.h .h" DNode* head; DNode* tail; int num_items;
void void pu push_ h_fr fron ont(const const T& i T& ite tem) m) { { hea head = ne d = new w DNode DNode(it (item, NU em, NULL, LL, head) head); ; // Ste // Step 1 p 1 if if ( (head head->n >nex ext ! != = NU NULL) LL) head head->next >next->prev prev = = hea ead; d; // S // Ste tep p 2 if if ( (tail tail = == = NULL NULL) ) // // Lis List t wa was em s empt pty. y. ta tail = il = h hea ead; d; nu num_ m_item items++; ++; }
void void pu push_ h_ba back ck(con onst st T& T& it item em) ) { if if ( (tail tail ! != = NULL NULL) ) { // // Ste Step p 1 tail tail->n >nex ext t = n new ew DN DNode de(i (ite tem, t m, tai ail, l, NUL NULL) L); ; // // Ste Step p 2 ta tail = il = t tai ail->next; >next; nu num_it m_item ems++; ++; } } el else { se { // // L List st w was as emp empty ty. pu push_f sh_fro ront nt(ite (item) m); } }
iterator insert(iterator pos, const T& item) { /* Check for s /* Check for special c pecial cases */ ases */ if (pos.current == head) { // insert a // insert at head t head push_front(item); return begin(); } else if (pos.current == NULL) { // Past the last node. push_back(item); return iterator(this, tail); } /* conti /* continued on nued on next sli next slide */ de */
/* conti /* continued fro nued from previo m previous slide us slide */ */ /* Create a new node linked before the node referenced by pos (insert in middle) */ DNode* new_node = new DNode(item, pos.current->prev, pos.current); // // S Ste tep 1 1 pos.current->prev->next = new_node; // Step 2 // Step 2 pos.current->prev = new_node; // Step // Step 3 num_items++; return iterator(this, new_node); }
iterator insert(iterator pos, const T& item) { // // Che Check fo ck for s r spec pecial c ial case ases if (pos.current == head) { push_front(item); return begin(); } else if (pos.current == NULL) { // Past t t the he las last nod t node. e. push_back(item); return iterator(this, tail); } // / Cre reate a te a ne new n node l de link nked d befor efore n node de refe referen enced ed by p by pos. s. DNode* new_node = new DNode(item, pos.current->prev, pos.current); // St Step ep 1 // // Upd Update l ate link inks pos.current->prev->next = new_node; // // S Step ep 2 pos.current->prev = new_node; // Step tep 3 3 num_items++; return iterator(this, new_node); }
Variation: circular cular list st link the last node to the first node can be singl gly-linked linked or doubly bly-linked linked Another simplification add a dummy mmy first st node This is is s the imp mplemen lementation tation in Maciel ciel, , Chap apter ter 13
/* repr presen esentation tation for nodes des */ template <class T> class ListN stNod ode // // T is is the e typ ype e of of elem ement ent stored ored in the e list. ist. { friend class List<T>; private: T element; ListNode<T> * next; ListNode<T> * previous; }; Figure 13.1: A class of nodes, Maciel, p. 228
template <class T> class List st // // T is is the e typ ype e of of elem ement ent stored ored in the e list. ist. { public: // on next xt slide ide private: ListNode<T> * p_head_node; }; Figure 13.2: The class List, Maciel, p. 228
// pub ublic lic interface terface for class ass List st public: List() { p_head_node = new ListNode<T>; p_head_node->next = p_head_node->previous = p_head_node; } // / continue tinued d on next t slide lide Figure 13.3: A first version of List, Maciel, p. 230
// pub ublic lic interface terface for class ass List, st, continued tinued T & back() { return p_head_node->previous->element;} const T & back() const { return p_head_node->previous->element; } void push_back( const T & new_element ); void pop_back(); void test_print() const; // for testi ting ng only ly private: // as in Fi Figure gure 13.2 Figure 13.3: A first version of List, Maciel, p. 230
template<class T> void List<T>::test_print() const { for ( ListNode<T> * p_node = p_head_node->next; p_node != p_head_node; p_node = p_node->next ) { cout << p_node->element << ' '; } cout << endl; } Figure 13.4: The internal test driver, Maciel, p. 230
Properties of List iterator, itr dereferencing a List iterator should yield an element of the list, so, (*itr) should be of type T incrementing a List iterator should advance the iterator to the next node on the list so, (++itr) should move the iterator to the next node iterator ators s are simil ilar ar to, but not the same e as pointer nters! s!
template <class T> class ListIterator { friend class List<T>; public blic: : // on next t slide lide private ivate: : ListIterator( ListNode<T> * p ) { p_current_node = p; } ListNode<T> * p_current_node; /* points to the node that contains the element that the iterator currently “points” to }; Figure 13.7: declaration of ListIterator, Maciel, p. 235
// template mplate <c <clas lass T> > class ass ListI stIter terator ator, , continu tinued ed pub ublic lic: : ListIterator() { p_current_node = NULL; } T & operator*() { return p_current_node->element; } bool operator!=( const ListIterator & rhs ) const { return (p_current_node != rhs.p_current_node); } ListIterator & operator++(); // prefix version (++itr) ListIterator & operator--(); ListIterator operator++(int); // postfix version (itr++) ListIterator operator--(int); Figure 13.7: public interface for ListIterator, Maciel, p. 235
add d a typedef edef declarati laration on to class ass List<T ist<T> template <class T> class List { public: typed pedef ListI stIter terator ator<T <T> > iterator; erator; modif dify y List istNode Node to gr grant ant friendshi iendship p to ListI istIterator terator template <class T> class ListNode { friend class List<T>; frie riend d class ass ListIterator stIterator<T <T>; >;
Recommend
More recommend