diff --git a/labs/07_list_implementation/README.md b/labs/07_list_implementation/README.md index b0211b8..2835680 100644 --- a/labs/07_list_implementation/README.md +++ b/labs/07_list_implementation/README.md @@ -3,7 +3,7 @@ ## Checkpoint 1 *estimate: 20-30 minutes* -The implementation of the dslist class is incomplete. In particular, the class is missing the destroy_list +The implementation of the dslist class in [dslist.h](dslist.h) is incomplete. In particular, the class is missing the destroy_list private member function that is used by the destructor and the clear member function. The provided test case in [checkpoint1.cpp](checkpoint1.cpp) works “fine”, so what’s the problem? diff --git a/labs/07_list_implementation/dslist.h b/labs/07_list_implementation/dslist.h new file mode 100644 index 0000000..c59ef55 --- /dev/null +++ b/labs/07_list_implementation/dslist.h @@ -0,0 +1,268 @@ +#ifndef dslist_h_ +#define dslist_h_ +// A simplified implementation of the STL list container class, +// including the iterator, but not the const_iterators. Three +// separate classes are defined: a Node class, an iterator class, and +// the actual list class. The underlying list is doubly-linked, but +// there is no dummy head node and the list is not circular. +#include + +// ----------------------------------------------------------------- +// NODE CLASS +template +class Node { +public: + Node() : next_(NULL), prev_(NULL) {} + Node(const T& v) : value_(v), next_(NULL), prev_(NULL) {} + + // REPRESENTATION + T value_; + Node* next_; + Node* prev_; +}; + +// A "forward declaration" of this class is needed +template class dslist; + +// ----------------------------------------------------------------- +// LIST ITERATOR +template +class list_iterator { +public: + // default constructor, copy constructor, assignment operator, & destructor + list_iterator(Node* p=NULL) : ptr_(p) {} + // NOTE: the implicit compiler definitions of the copy constructor, + // assignment operator, and destructor are correct for this class + + // dereferencing operator gives access to the value at the pointer + T& operator*() { return ptr_->value_; } + + // increment & decrement operators + list_iterator& operator++() { // pre-increment, e.g., ++iter + ptr_ = ptr_->next_; + return *this; + } + list_iterator operator++(int) { // post-increment, e.g., iter++ + list_iterator temp(*this); + ptr_ = ptr_->next_; + return temp; + } + list_iterator& operator--() { // pre-decrement, e.g., --iter + ptr_ = ptr_->prev_; + return *this; + } + list_iterator operator--(int) { // post-decrement, e.g., iter-- + list_iterator temp(*this); + ptr_ = ptr_->prev_; + return temp; + } + // the dslist class needs access to the private ptr_ member variable + friend class dslist; + + // Comparions operators are straightforward + bool operator==(const list_iterator& r) const { + return ptr_ == r.ptr_; } + bool operator!=(const list_iterator& r) const { + return ptr_ != r.ptr_; } + +private: + // REPRESENTATION + Node* ptr_; // ptr to node in the list +}; + +// ----------------------------------------------------------------- +// LIST CLASS DECLARATION +// Note that it explicitly maintains the size of the list. +template +class dslist { +public: + // default constructor, copy constructor, assignment operator, & destructor + dslist() : head_(NULL), tail_(NULL), size_(0) {} + dslist(const dslist& old) { copy_list(old); } + dslist& operator= (const dslist& old); + ~dslist() { destroy_list(); } + + typedef list_iterator iterator; + + // simple accessors & modifiers + unsigned int size() const { return size_; } + bool empty() const { return head_ == NULL; } + void clear() { destroy_list(); } + + // read/write access to contents + const T& front() const { return head_->value_; } + T& front() { return head_->value_; } + const T& back() const { return tail_->value_; } + T& back() { return tail_->value_; } + + // modify the linked list structure + void push_front(const T& v); + void pop_front(); + void push_back(const T& v); + void pop_back(); + + iterator erase(iterator itr); + iterator insert(iterator itr, const T& v); + iterator begin() { return iterator(head_); } + iterator end() { return iterator(NULL); } + +private: + // private helper functions + void copy_list(const dslist& old); + void destroy_list(); + + //REPRESENTATION + Node* head_; + Node* tail_; + unsigned int size_; +}; + + // ----------------------------------------------------------------- +// LIST CLASS IMPLEMENTATION +template +dslist& dslist::operator= (const dslist& old) { + // check for self-assignment + if (&old != this) { + destroy_list(); + copy_list(old); + } + return *this; +} + +template +void dslist::push_front(const T& v) { + + + + + +} + +template +void dslist::pop_front() { + + + + +} + +template +void dslist::push_back(const T& v) { + Node* newp = new Node(v); + // special case: initially empty list + if (!tail_) { + head_ = tail_ = newp; + } else { + // normal case: at least one node already + newp->prev_ = tail_; + tail_->next_ = newp; + tail_ = newp; + } + ++size_; +} + +template +void dslist::pop_back() { + + + + + +} + +// do these lists look the same (length & contents)? +template +bool operator== (dslist& left, dslist& right) { + if (left.size() != right.size()) return false; + typename dslist::iterator left_itr = left.begin(); + typename dslist::iterator right_itr = right.begin(); + // walk over both lists, looking for a mismatched value + while (left_itr != left.end()) { + if (*left_itr != *right_itr) return false; + left_itr++; right_itr++; + } + return true; +} + +template +bool operator!= (dslist& left, dslist& right){ return !(left==right); } + template +typename dslist::iterator dslist::erase(iterator itr) { + assert (size_ > 0); + --size_; + iterator result(itr.ptr_->next_); + // One node left in the list. + if (itr.ptr_ == head_ && head_ == tail_) { + head_ = tail_ = 0; + } + // Removing the head in a list with at least two nodes + else if (itr.ptr_ == head_) { + head_ = head_->next_; + head_->prev_ = 0; + } + // Removing the tail in a list with at least two nodes + else if (itr.ptr_ == tail_) { + tail_ = tail_->prev_; + tail_->next_ = 0; + } + // Normal remove + else { + itr.ptr_->prev_->next_ = itr.ptr_->next_; + itr.ptr_->next_->prev_ = itr.ptr_->prev_; + } + delete itr.ptr_; + return result; +} + + +template +typename dslist::iterator dslist::insert(iterator itr, const T& v) { + ++size_ ; + Node* p = new Node(v); + p->prev_ = itr.ptr_->prev_; + p->next_ = itr.ptr_; + itr.ptr_->prev_ = p; + if (itr.ptr_ == head_) + head_ = p; + else + p->prev_->next_ = p; + return iterator(p); +} + + +template +void dslist::copy_list(const dslist& old) { + size_ = old.size_; + // Handle the special case of an empty list. + if (size_ == 0) { + head_ = tail_ = 0; + return; + } + // Create a new head node. + head_ = new Node(old.head_->value_); + // tail_ will point to the last node created and therefore will move + // down the new list as it is built + tail_ = head_; + // old_p will point to the next node to be copied in the old list + Node* old_p = old.head_->next_; + // copy the remainder of the old list, one node at a time + while (old_p) { + tail_->next_ = new Node(old_p->value_); + tail_->next_->prev_ = tail_; + tail_ = tail_->next_; + old_p = old_p->next_; + } +} + +template +void dslist::destroy_list() { + + + + + + + +} + +#endif