Question
Summary Implement a template for a doubly linked list called DList along with iterators to access the list. In your implementation, you can choose to
Summary
Implement a template for a doubly linked list called DList along with iterators to access the list. In your implementation, you can choose to use sentinel nodes or not use sentinel nodes. That is entirely up to you.
Nodes in this list will have a pointer not only to the next node but also a pointer to the previous node.
The DList class has the following member functions. Each function must meet the big-O runtime specified. Unless otherwise stated n refers to number of nodes within the linked list.:
DList();
constructor, creates empty DList
O(1)
iterator begin();
returns iterator to Node containing the first piece of data in the linked list
O(1)
iterator end();
returns iterator to the Node after the node containing the last piece of data of the linked list
O(1)
const_iterator begin() const;
returns const_iterator to to Node containing the first piece of data in the linked list
O(1)
const_iterator end() const;
returns const_iterator to the Node after the node containing the last piece of data of the linked list
O(1)
void push_front(const T& data);
adds a node containing data to the front of the linked list
O(1)
void push_back(const T& data);
adds a node containing data to the back of the linked list
O(1)
void pop_front();
removes the first node from the linked list
O(1)
void pop_back();
removes the last node from the linked list
O(1)
iterator insert(const T& data,iterator it);
adds a node containing data to the linked list such that the new node goes before the node referred to by it
Note that it is allowed to be equivalent to end().
returns iterator to newly added node
O(1)
iterator erase(iterator it);
removes the node referred to by it
returns iterator to node after the node removed
O(1)
iterator erase(iterator first, iterator last);
removes the nodes between the nodes referred to by iterator first to last. This includes the node referred to by first but NOT the node referred to by last.
returns iterator to last
O(n) where n is the number of nodes between first and last
iterator search(const T& data); const_iterator search(const T& data) const;
returns iterator to the node containing data. If data is not found, returns end()
O(n)
bool empty() const;
function returns true if the list is empty, false otherwise
O(1)
int size() const;
function returns number of pieces of data stored in the list
O(1)
~DList(); DList(const DList&); DList& operator=(const DList&); DList(DList&&); DList& operator=(DList&&);
Your linked list must also implement destructor, copy constructor, assignment operator, move constructor, move operator.
runtime for destructor, copy constructor and assignment operator must not exceed O(n)
runtime for move constructor/operator must not exceed O(1)
Iterator
The idea of an iterator is to provide a means to traverse your class. In the STL, different classes like vectors or list all have iterators that help you iterate through your list. For the linked list, you will also write an iterator class.
You will need two iterators. a const_iterator and an iterator which is derived from const_iterator. For both operators, the following public members/operators are needed. You are welcome to add any other private or protected members as you see fit:
iterator(); const_iterator();
constructors, returns iterators to nullptrs O(1)
iterator operator++(); const_iterator operator++() const; iterator operator++(int); const_iterator operator++(int);
prefix and postfix ++ operator
makes iterator point to the next node in the list.
return as appropriate for each operator
O(1)
iterator operator--(); const_iterator operator--() const; iterator operator--(int); const_iterator operator--(int);
prefix and postfix operator --
increments iterator so that it points to previous node in list
return as appropriate for each operator
O(1)
operator==
returns true if two iterators point at the same node, false otherwise
operator !=
returns true if two iterators point at different nodes, false otherwise
O(1)
const T& operator*()const; (in both iterator and const_iterator) T& operator*(); (only in iterator)
dereferencing operator, returns the data in the node pointed to by iterator
O(1)
-------------------------------------------------------------------------------------------------------
MY CODE:
template
class DList{ struct Node{
T data_; Node* next_; Node* prev_;
Node(const T& data=T{},Node* nx=nullptr,Node* pr=nullptr){
data_ = data; next_ = nx; prev_ = pr; } };
Node* front_; Node* back_;
public: class const_iterator{ friend class DList;
protected:
Node* curr_; const_iterator(Node* n){ curr_=n; }
public: const_iterator(){ curr_= nullptr; }
const_iterator operator++(){ if(curr_){ curr_=curr_->next_; } return *this; }
const_iterator operator++(int){ const_iterator old=*this; if(curr_){ curr_=curr_->next_; } return old; }
const_iterator operator--(){ if(curr_){ curr_=curr_->prev_; } return *this; }
const_iterator operator--(int){ const_iterator old=*this; if(curr_){ curr_=curr_->prev_; } return old; }
bool operator==(const_iterator rhs){ return curr_==rhs.curr_; } bool operator!=(const_iterator rhs){ return curr_!=rhs.curr_; } const T& operator*()const{ return curr_->data_; } }; class iterator:public const_iterator{ friend class DList; iterator(Node* n):const_iterator(n){} public: iterator(){} iterator operator++(){ if(this->curr_){ this->curr_=this->curr_->next_; } return *this; } iterator operator++(int){ iterator old=*this; if(this->curr_){ this->curr_=this->curr_->next_; } return old; } iterator operator--(){ if(this->curr_){ this->curr_=this->curr_->prev_; } return *this; } iterator operator--(int){ iterator old=*this; if(this->curr_){ this->curr_=this->curr_->prev_; } return old; } T& operator*(){ return this->curr_->data_; } const T& operator*()const{ return this->curr_->data_; } }; DList(); ~DList(); DList(const DList& rhs); DList& operator=(const DList& rhs); DList(DList&& rhs); DList& operator=(DList&& rhs); iterator begin(){ return iterator(front_);} iterator end(){ return iterator(nullptr);} const_iterator begin() const{ return iterator(front_);} const_iterator end() const{ return iterator(nullptr);} void push_front(const T& data); void push_back(const T& data); void pop_front(); void pop_back(); iterator insert(const T& data, iterator it); iterator search(const T& data); const_iterator search(const T& data) const; iterator erase(iterator it); iterator erase(iterator first, iterator last); bool empty() const; int size() const;
private: Node* back_; Node* front_; friend class DList;
};
template
front_= nullptr; back_ = nullptr; } template
Node* curr=front_; while(curr != back_){ front_ = front_->next_; delete curr; curr = front_; }
} template
const Node* curr = rhs.front_; Node* temp = nullptr;
if (curr != back_) { front_ = new Node(curr->data_); temp = front_; curr = curr->next_; } while(curr != back_) { Node* nn = new Node(curr->data_); temp->next_ = nn; temp = temp->next_; curr = curr->next_; }
} template
} template
}
template
}
template
Node* nn=new Node(data,front_,nullptr); if(front_!=nullptr){ //make front's prev point to new node front_->prev_ = nn; } else{
back_=nn; } //make front point to new node front_=nn; } template
Node* newN = new Node(data, nullptr, back_); if( back_ != nullptr){ back_->next_ = newN; } else{ front_ = newN; } back_ = newN; } } template
if(front_ != nullptr){ Node* rm = front_; if(front_!=back_){ //make sure we have more than one node front_=front_->next_; //front_=rm->next_; front_->prev_=nullptr; } else{ front_=back_=nullptr; } delete rm; } } template
if(back_ != nullptr){ Node* temp = back_; if(front_!=back_){ back_->prev_->next_ = nullptr; back_ = back_->prev_; //std::cout << "new back data: " << back_->data_; } else{ front_ = back_ = nullptr; } delete temp; }
}
template
}
template
}
template
}
template
}
template
} template
return front_->next_ == nullptr; } template
}
-------------------------------------------------------------
MAIN TESTER
#include "a1q1start.h" #include
struct Record{ char word_[30]; int count_; }; ostream& operator<<(ostream& os, const Record rec){ os << rec.word_; return os; } bool operator==(const Record& a,const Record& b){ bool rc=false; if(strcmp(a.word_,b.word_)==0 && a.count_==b.count_){ rc=true; } return rc; } bool operator!=(const Record& a,const Record& b){ return !(a==b); } bool operator <(const Record& a, const Record& b){ bool rc=false; if(strcmp(a.word_,b.word_) < 0){ rc=true; } return rc; }
template
int main(void){ const int cap=10000; const int numSearches=200; Record data[20]={ {"the",1}, {"quick",2}, {"brown ",3}, {"fox",4}, {"jumped",5}, {"over",6}, {"lazy",7}, {"dog",8}, {"Calvin",9}, {"and",10}, {"Hobbes",11}, {"night",12}, {"watch",13}, {"captain",14}, {"carrot",15}, {"lilac",16}, {"lavender",17}, {"lily",18}, {"coffee",19}, {"tea",20} }; int intData[cap];
//these array will mirror what happens to LL Record mirror[20]; int intMirror[cap]; for(int i=0;i DList bool passtest=true; int numPassed=0; /* Test constructors, begin and end functions*/ cout << "test 1: create list empty list, check begin() and end()" << endl; if((recList.begin() != recList.end()) || (intList.begin() != intList.end())){ cout << "error 1: check your constructor, begin() and end() functions" << endl; passtest=false; } else{ numPassed++; } if(passtest){ for(int i=0;i<5;i++){ addFront(data[i],mirror,i); recList.push_front(data[i]); } for(int i=5;i<10;i++){ addBack(data[i],mirror,i); recList.push_back(data[i]); } DList DList if(passtest){ numPassed++; cout << "test 4: create a duplicate of the lists with copy constructor, ensure they match" << endl; if(!checkList(recList,mirror,20)){ passtest=false; cout << "Error 4a: Bug in copy constructor" << endl; } if(!checkList(intList,intMirror,cap)){ passtest=false; cout << "Error 4b: Bug in copy constructor" << endl; } } if(passtest){ numPassed++; cout << "test 5: test search() function" << endl; for(int i=0;i<20;i++){ DList if(passtest){ numPassed++; cout << "test 6: test erase function" << endl; DList if(passtest){ numPassed++; cout << "test 9: test assignment operator (deep copy)" << endl; recCopy2.erase(recCopy2.begin()); intCopy2.erase(intCopy2.begin()); if(!checkList(recList,mirror,15)|| recList.empty() || recList.size()!=15){ passtest=false; cout << "Error 9a: Bug in = operator, no deepcopy?" << endl; } if(!checkList(intList,intMirror,cap-104)|| intList.empty() || intList.size()!=cap-104){ passtest=false; cout << "Error 9b: Bug in = operator,no deep copy?" << endl; } } if(passtest){ numPassed++; cout << "test 10: search for removed items" << endl; int pick[2]={0,19}; for(int i=0;i<2;i++){ auto it =recList.search(data[pick[i]]); if(it!=recList.end()){ cout << "Error 10a: Bug in search, returned iterator is not correct" << endl; passtest=false; } } } if(passtest){ int pick[4]={0,1,cap-1,cap-2}; for(int i=0;i<4;i++){ auto it = intList.search(intData[pick[i]]); if(it != intList.end()){ passtest=false; cout << "Error 10b: Bug in search."<< endl; } } } if(passtest){ numPassed++; cout << "test 11: test erase(front,back) function" << endl; DList recCopy2.erase(it,it2); removeItem(tmp,4,14); removeItem(tmp,3,13); removeItem(tmp,2,12); if(!checkList(recCopy2,tmp,11)){ passtest=false; cout << "Error 11a: Bug erase(it) function" << endl; #if VERBOSE >= 1 printLists(recCopy2,tmp,11); #endif } if(!checkList(recList,mirror,15)){ passtest=false; cout << "Error 11b: assignment operator, (deep copy not made?)" << endl; #if VERBOSE >= 1 printLists(recList,mirror,15); #endif } } if(passtest){ numPassed++; cout << "test 12: test erase(it,end()) function" << endl; DList recCopy2.erase(it,recCopy2.end()); removeItem(tmp,14,15); removeItem(tmp,13,14); removeItem(tmp,12,13); removeItem(tmp,11,12); if(!checkList(recCopy2,tmp,11)){ passtest=false; cout << "Error 12a: Bug erase(first,last) function" << endl; #if VERBOSE >= 1 printLists(recCopy2,tmp,11); #endif } if(!checkList(recList,mirror,15)){ passtest=false; cout << "Error 12b: assignment operator, (deep copy not made?)" << endl; #if VERBOSE >= 1 printLists(recList,mirror,15); #endif } } DList if(!checkList(recCopy3,mirror,15)){ passtest=false; cout << "Error 13a: Bug in move constructor" << endl; #if VERBOSE >= 1 printLists(recCopy3,mirror,15); #endif } if(recList.begin() == recCopy3.begin()){ passtest=false; cout << "Error 13b: Bug in move constructor" << endl; cout << "original and copy both refer to same list" << endl; } } if(passtest){ numPassed++; recList=recCopy3; cout << "test 14: test move assignment operator" << endl; recCopy3=std::move(recList); if(!checkList(recCopy3,mirror,15)){ passtest=false; cout << "Error 14a: Bug in move assignment operator" << endl; #if VERBOSE >= 1 printLists(recCopy3,mirror,15); #endif } if(recList.begin() == recCopy3.begin()){ passtest=false; cout << "Error 14b: Bug in move assignment operator" << endl; cout << "original and copy both refer to same list" << endl; } } if(passtest){ numPassed++; } if(numPassed == 14){ cout << "Testing for Assignment 1, part 1 completed successfully" << endl; cout << "14/14 tests passed" << endl; } else{ cout << numPassed << " / 14 tests passed. Looks like you still" << endl; cout << "have some work to do" << endl; } return 0; } template template template Any help would be useful as this is also a study guide for an upcoming test, Thank you greatly.
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started