From a838530abefcf4a8e2e0aabaa97696974a20c7a8 Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Fri, 6 Oct 2023 13:38:36 -0400 Subject: [PATCH] adding ds list code --- .../11_list_implementation/dslist_handout.h | 245 ++++++++++++++++++ lectures/11_list_implementation/list.h | 206 +++++++++++++++ lectures/11_list_implementation/list_main.cpp | 83 ++++++ 3 files changed, 534 insertions(+) create mode 100644 lectures/11_list_implementation/dslist_handout.h create mode 100644 lectures/11_list_implementation/list.h create mode 100644 lectures/11_list_implementation/list_main.cpp diff --git a/lectures/11_list_implementation/dslist_handout.h b/lectures/11_list_implementation/dslist_handout.h new file mode 100644 index 0000000..d6c310b --- /dev/null +++ b/lectures/11_list_implementation/dslist_handout.h @@ -0,0 +1,245 @@ +#ifndef dslist_h_ +#define dslist_h_ +// A simplified implementation of a generic 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() : ptr_(NULL) {} + list_iterator(Node* p) : ptr_(p) {} + list_iterator(const list_iterator& old) : ptr_(old.ptr_) {} + list_iterator& operator=(const list_iterator& old) { + ptr_ = old.ptr_; return *this; } + ~list_iterator() {} + + // 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) { this->copy_list(old); } + dslist& operator= (const dslist& old); + ~dslist() { this->destroy_list(); } + + // simple accessors & modifiers + unsigned int size() const { return size_; } + bool empty() const { return head_ == NULL; } + void clear() { this->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(); + + typedef list_iterator iterator; + 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) { + this->destroy_list(); + this->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) { + + + + + +} + +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) { + + + + + + + + + + + + +} + +template +typename dslist::iterator dslist::insert(iterator itr, const T& v) { + + + + + + + + + + +} + +template +void dslist::copy_list(const dslist& old) { + + + + + + + + + + + + + + + + +} + +template +void dslist::destroy_list() { + + + + + + + +} + +#endif diff --git a/lectures/11_list_implementation/list.h b/lectures/11_list_implementation/list.h new file mode 100644 index 0000000..c742cad --- /dev/null +++ b/lectures/11_list_implementation/list.h @@ -0,0 +1,206 @@ +template +class Node { + public: + T value; + Node* next; + Node* prev; + private: +}; + +template class dslist; + +template +class list_iterator { + public: + // default constructor + list_iterator(){ + ptr = NULL; + } + list_iterator(Node* p) { + ptr = p; + } + // assignment constructor + list_iterator& operator=(const list_iterator& other){ + this->ptr = other.ptr; + return (*this); + } + // derefencing operator + T& operator*(){ + return (ptr->value); + } + // pre-increment + list_iterator& operator++(){ + this->ptr = this->ptr->next; + return (*this); + } + // post-increment + list_iterator operator++(int){ + list_iterator temp = (*this); + this->ptr = this->ptr->next; + return temp; + } + // operator == + bool operator==(const list_iterator& other){ + return (this->ptr == other.ptr); + } + // operator != + bool operator!=(const list_iterator& other){ + return (this->ptr != other.ptr); + } + + friend class dslist; + private: + Node* ptr; +}; + +template +class dslist { + public: + typedef list_iterator iterator; + typedef unsigned int size_type; + // default constructor + dslist(){ + head = nullptr; + tail = nullptr; + size_ = 0; + } + + // copy constructor + dslist(const dslist& other){ + // here we must initialize head and tail, because we will use them in push_back(). + head = nullptr; + tail = nullptr; + size_ = other.size_; + iterator itr = other.begin(); + while(itr != other.end()){ + this->push_back(*itr); + itr++; + } + } + + // x=(w=v) + dslist& operator=(const dslist& other){ + head = nullptr; + tail = nullptr; + size_ = other.size_; + iterator itr = other.begin(); + while(itr != other.end()){ + this->push_back(*itr); + itr++; + } + } + + ~dslist(){ + iterator itr = this->begin(); + while(itr != this->end()){ + iterator itr2 = itr; + itr2++; + delete itr.ptr; + itr = itr2; + } + } + + size_type size(){ + return size_; + } + + void push_back(const T& value){ + Node *temp = new Node; + temp->value = value; + temp->next = NULL; + temp->prev = tail; + // if the list was originally empty + if(head == nullptr){ + head = temp; + tail = temp; + }else{ + tail->next = temp; + tail = temp; + } + size_ = size_ + 1; + } + + void pop_back(); + + // just like push_back(), it just takes a value as its parameter. + void push_front(const T& value){ + Node *temp = new Node; + temp->value = value; + temp->next = head; + temp->prev = nullptr; + if(head == nullptr){ + head = temp; + tail = temp; + }else{ + head->prev = temp; + head = temp; + } + size_ = size_ + 1; + } + + void pop_front(); + + /* iterator implementation */ + void erase(iterator itr){ + dslist::iterator itr2 = itr; + itr2++; + while (itr2 != this->end()) { + *itr = *itr2; + itr++; + itr2++; + } + this->pop_back(); + } + + void insert(iterator itr, const T& value){ + Node* temp = new Node; + temp->value = value; + temp->next = itr.ptr->next; + temp->prev = itr.ptr; + itr.ptr->next = temp; + // if inserting after the last element + if(itr.ptr->next != nullptr){ + itr.ptr->next->prev = temp; + } + } + + iterator begin() const { + return list_iterator(head); + } + + iterator end() const { + return list_iterator((Node*)nullptr); + //return list_iterator((Node*)NULL); + //return list_iterator(NULL); + } + + private: + // pointing to head node and tail node. + Node* head; + Node* tail; + + unsigned int size_; // current size + +}; + +// TODO: handle the case where the list is empty, i.e., tail==nullptr and can't be dereferenced. +template +void dslist::pop_back(){ + Node * temp = tail; + tail = tail->prev; + tail -> next = NULL; + // delete the original tail. + delete temp; + size_ = size_ - 1; +} + +// TODO: handle the case where the list is empty, i.e., head==nullptr and can't be dereferenced. +template +void dslist::pop_front(){ + Node * temp = head; + head = head->next; + head->prev = nullptr; + // delete the original head. + delete temp; + size_ = size_ - 1; +} diff --git a/lectures/11_list_implementation/list_main.cpp b/lectures/11_list_implementation/list_main.cpp new file mode 100644 index 0000000..d61817e --- /dev/null +++ b/lectures/11_list_implementation/list_main.cpp @@ -0,0 +1,83 @@ +#include +//#include + +#include "list.h" + +int main(){ + + // dslist is a template, not a type. + dslist teams; + teams.push_back("rpi"); + teams.push_back("wpi"); + teams.push_back("yale"); + teams.push_back("brown"); + teams.push_back("cornell"); + teams.push_back("colgate"); + teams.push_back("miami"); + teams.push_back("colorado"); + teams.push_back("harvard"); + + // we can use a type alias defined inside a class even if there is no object of that class. The type alias becomes part of the class's scope and can be used anywhere in your code where the class's scope is visible. although no object of dslist is created in this code, the type alias size_type is still accessible because it is part of the class's scope. + dslist::iterator itr; + for(itr = teams.begin(); itr != teams.end(); itr++){ + std::cout << *itr << std::endl; + } + std::cout<<"==============="< ll; + ll.push_back(2.5); + ll.push_back(3.4); + int i = 0; + dslist::iterator itr2 = ll.begin(); + for (i=0, itr2 = ll.begin(); itr2 != ll.end(); itr2++, i++){ + std::cout << "ll[" << i << "] is " << *itr2 << std::endl; + } + + // copy a list - calls copy constructor. + dslist u(ll); + itr2 = u.begin(); + itr2++; + u.insert(itr2, 6.5); + u.insert(itr2, 4.8); + for (i=0, itr2 = u.begin(); itr2 != u.end(); itr2++, i++){ + std::cout << "u[" << i << "] is " << *itr2 << std::endl; + } + + // equivalent to list w(v), w is a copy of the elements in v. + // we use the const keyword in front of a variable definition to indicate that the value of the variable cannot be changed after it is initialized. + dslist w = ll; + for (i=0, itr2 = w.begin(); itr2 != w.end(); itr2++, i++){ + std::cout << "w[" << i << "] is " << *itr2 << std::endl; + } + +}