1 / 53

Generic Positional Containers and Double-Ended Queues

Generic Positional Containers and Double-Ended Queues. Generic Positional Containers. A generic container C<T> which is Organized and accessed by position vector[i] = ‘a’; list.insert(I, ‘a’); Can insert any T object at any position in C<T>

payton
Download Presentation

Generic Positional Containers and Double-Ended Queues

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Generic Positional Containers and Double-Ended Queues

  2. Generic Positional Containers • A generic container C<T> which is • Organized and accessed by position • vector[i] = ‘a’; • list.insert(I, ‘a’); • Can insert any T object at any position in C<T> • Can remove any T object at any position in C<T> • Can support • push_front(), pop_front(), front() • push_back(), pop_back(), back() • Examples: List, Deque

  3. Double-Ended Queue • Deque (pronounced ‘Deck’) • Deque operations • Push/Pop at either end • Retrieve data from either end • Proper type

  4. Specifying Deque<T> • Requirements for Deque • O(1)average runtime, O(size()) space • push_front(t), pop_front(), front() • push_back(t), pop_back(), back() • O(1) time and space for iterator operations • Random access iterator ([])

  5. Deque<T> Implementation Plan • Circular array • Protected array content of size content_size • Content wraps around the end of the array to the beginning. • Illusion: content[content_size] == content[0]

  6. begin end Deque<T> D Illustrated • content_size = 8 • D.empty() == true content

  7. begin end Deque<char> D Illustrated (2) • content_size = 8 • D.push_back(‘M’) content

  8. begin end Deque<char> D Illustrated (3) • content_size = 8 • D.push_back(‘e’) content

  9. begin end Deque<char> D Illustrated (4) • content_size = 8 • D.push_back(‘r’) content

  10. begin end Deque<char> D Illustrated (5) • content_size = 8 • D.push_back(‘r’) content

  11. begin end Deque<char> D Illustrated (6) • content_size = 8 • D.push_back(‘y’) content

  12. begin end Deque<char> D Illustrated (7) • content_size = 8 • D.pop_front() • O(1) content

  13. begin end Deque<char> D Illustrated (8) • content_size = 8 • D.pop_front() content

  14. begin end Deque<char> D Illustrated (9) • content_size = 8 • D.push_back(‘G’) content

  15. begin end Deque<char> D Illustrated (10) • content_size = 8 • D.push_back(‘o’) • D.size() == (7 – 2 + 8) % 8 content

  16. begin end Deque<char> D Illustrated (11) • content_size = 8 • D.push_back(‘A’) • D.size() = (0 – 2 + 8) % 8 content

  17. begin end Deque<char> D Illustrated (12) • content_size = 8 • D.push_back(‘r’) • D.size() = (1 – 2 + 8) % 8 content

  18. begin end Deque<char> D Illustrated (13) • D.size() == content_size – 1 • Now what? • Return full or • Double the capacity (as with Vector). content

  19. Deque<T> Implementation Plan (2) • Relative Indexing • Protected integers • begin, end • Bracket [] Operator • Similar to Vector • Element position relative to begin • Front element is content[begin] • Back element is content[end – 1] • Size is (end – begin + content_size) % content_size

  20. Deque<T>::iterator Implementation Plan • Public interface • Start with the public interface of List<T>::iterator • Add bracket operator

  21. Defining Deque<T> template <typename T> class Deque { public: typedef T value_type; // type definitions typedef DequeIterator<T> iterator; Deque(); // constructors and deconstructor Deque(size_t, const T&); Deque(const Deque<T>&); ~Deque(); // display functions void Display(ostream& os, char ofc = ‘\0’) const; void Dump(ostream& os) const;

  22. Defining Deque<T> (2) int empty() const; // container read-only routines size_t size() const; T& front() const; T& back() const; T& operator[] (size_t) const; int push_front(const T&); // container write routines int pop_front(); int push_back(const T&); int pop_back(); Deque<T>& operator=(const Deque<T>&);

  23. Defining Deque<T> (3) friend class DequeIterator<T>; // iterator support iterator begin() const; iterator end() const; protected: T* content; size_t content_size, begin, end; };

  24. Defining Deque<T> (4) // operator overloads (friend status not required) template<class T> ostream& operator<<(ostream& os, const Deque<T>& a); template<class T> int operator==(const Deque<T>&, const Deque<T>&); template<class T> int operator!=(const Deque<T>&, const Deque<T>&);

  25. Defining DequeIterator<T> template <typename T> class DequeIterator { friend class Deque<T>; public: typedef T value_type; // terminology support DequeIterator(); // constructors DequeIterator(const Deque<T>& I); DequeIterator(const DequeIterator<T>& I); DequeIterator(const size_t& i); T& retrieve() const; // return ptr to current Tval int valid() const; // cursor is valid element

  26. Defining DequeIterator<T> (2) // various operators int operator==(const DequeIterator<T>& I2) const; int operator!=(const DequeIterator<T>& I2) const; T& operator*() const; // return reference to current Tval T& operator[] (size_t i) const; //return reference to Tval at index+i DequeIterator<T>& operator=(const DequeIterator<T>& I); DequeIterator<T>& operator++(); // prefix DequeIterator<T> operator++(int); // postfix DequeIterator<T>& operator--(); // prefix DequeIterator<T> operator--(int); // postfix

  27. Defining DequeIterator<T> (3) // pointer arithmetic long operator-(const DequeIterator<T>& I2) const; DequeIterator<T>& operator+=(long n); DequeIterator<T>& operator-=(long n); DequeIterator<T> operator+(long n) const; DequeIterator<T>& operator+=(int n); DequeIterator<T>& operator-=(int n); DequeIterator<T> operator+(int n) const; DequeIterator<T>& operator+=(unsigned long n); DequeIterator<T>& operator-=(unsigned long n); DequeIterator<T> operator+(unsigned long n) const; DequeIterator<T>& operator+=(unsigned int n); DequeIterator<T>& operator-=(unsigned int n); DequeIterator<T> operator+(unsigned int n) const;

  28. Defining DequeIterator<T> (3) protected: const Deque<T>* Qptr; size_t index; };

  29. Implementing Deque<T> • Default constructor template <typename T> Deque<T>::Deque() : content(0), begin(0), end(0), content_size(0) { content = new T[default_content_size]; if (content == 0) { // error } content_size = default_content_size; }

  30. Implementing Deque<T> (2) • Copy constructor template <typename T> Deque<T>::Deque(const Deque<T>& Q) : content_size(Q.content_size), begin(Q.begin), end(Q.end) { content = new T[content_size]; if (content == 0) { // error } for (size_t j = 0; j < content_size; j++) { content[j] = Q.content[j]; } }

  31. Implementing Deque<T> (3) • Read-only functions template <typename T> size_t Deque<T>::size() const { return (end – begin + content_size) % content_size; } template <typename T> T& Deque<T>::operator[] (size_t i) const { if (size() <= i) { // error } return content[(i + begin) % content_size]; }

  32. Implementing Deque<T> (4) • Display functions template <typename T> void Deque<T>::Display(ostream& os, char ofc) const { for (size_t j = 0; j < size(); ++j) { os << operator[](j); if (ofc != ‘\0’) { os << ofc; } } } template <typename T> void Deque<T>::Dump(ostream& os) const { for (size_t j = 0; j < content_size; ++j) { // print } }

  33. Implementing Deque<T> (5) • Read-only operator overloads template <typename T> ostream operator<<(ostream& os, const Deque<T>& Q) { Q.Display(os); return(os); } template <typename T> int operator==(const Deque<T>& Q1, const Deque<T>& Q2) { if (Q1.size() != Q2.size()) { return 0; } for (size_t j = 0; j < Q1.size(); ++j) { if (Q1[j] != Q2[j]) { return 0; } } return 1; }

  34. Implementing Deque<T> (6) • Read-only operator overloads template <typename T> int operator!=(const Deque<T>& Q1, const Deque<T>& Q2) { return !(Q1 == Q2); }

  35. Implementing Deque<T> (7) • Read-only functions template <typename T> int Deque<T>::empty() const { return begin == end; } template <typename T> void Deque<T>::Clear() { begin = end = 0; }

  36. Implementing Deque<T> (8) • Read-only functions template <typename T> T& Deque<T>::front() const { // check for empty Tdeque… return content[begin]; } template <typename T> T& Deque<T>::back() const { // check for empty Tdeque… if (end == 0) return content[content_size - 1]; return content[end - 1]; }

  37. Implementing Deque<T> (9) • Iterator support template <typename T> DequeIterator<T> Deque<T>::begin() const { Deque<T>::iterator I; I.Qptr = this; I.index = 0; return I; } template <typename T> DequeIterator<T> Deque<T>::end() const { Deque<T>::iterator I; I.Qptr = this; I.index = size(); return I; }

  38. Implementing Deque<T> (10) • Assignment template <typename T> Deque<T>& Deque<T>::operator=(const Deque<T>& Q) { if (this != &Q) { T* newcontent = new T[Q.content_size]; // check for allocation delete[] content; content = newcontent; content_size = Q.content_size; begin = Q.begin; end = Q.end; // copy queue elements } return *this; }

  39. Implementing Deque<T> (11) • push_back template <typename T> int Deque<T>::push_back(const T& Tval) { if (size() + 1 >= content_size) { // deque is full unsigned j, k; size_t newcontent_size = 2 * content_size; if (content_size == 0) newcontent_size = 2; T* newcontent = new T[newcontent_size]; // check for allocation error for (j = k = begin; j != end; j = (j + 1) % content_size, ++k) { newcontent[k] = content[j]; }

  40. Implementing Deque<T> (12) • push_back if (end < begin) {end += content_size; } delete[] content; content = newcontent; content_size = newcontent_size; } content[end] = Tval; end = (end + 1) % content_size; return 1; }

  41. Implementing Deque<T> (13) • push_front template <typename T> int Deque<T>::push_front(const T& Tval) { if (size() + 1 >= content_size) { // deque is full unsigned j, k; size_t newcontent_size = 2 * content_size; if (content_size == 0) newcontent_size = 2; T* newcontent = new T[newcontent_size]; // check for allocation error for (j = k = begin; j != end; j = (j + 1) % content_size, ++k) { newcontent[k] = content[j]; }

  42. Implementing Deque<T> (14) • push_front if (begin < end) { begin += content_size; } delete[] content; content = newcontent; content_size = newcontent_size; } begin = (begin – 1 + content_size) % content_size; content[begin] = Tval; return 1; }

  43. Implementing Deque<T> (15) • Pop routines template <typename T> int Deque<T>::pop_front() { if (begin == end) return 0; begin = (begin + 1) % content_size; return 1; } template <typename T> int Deque<T>::pop_back() { if (begin == end) return 0; end = (end – 1 + content_size) % content_size; return 1; }

  44. Implementing DequeIterator<T> • Constructors template <typename T> DequeIterator<T>::DequeIterator() : Qptr(0), index(0) { } template <typename T> DequeIterator<T>::DequeIterator(const Deque<T>& Q) : Qptr(&Q), index(0) { } template <typename T> DequeIterator<T>::DequeIterator(const DequeIterator<T>& I) : Qptr(I.Qptr), index(I.index) { }

  45. Implementing DequeIterator<T> (2) • Initialization routines template <typename T> void DequeIterator<T>::Initialize(const Deque<T>& Q) { Qptr = &Q; index = 0; } template <typename T> void DequeIterator<T>::rInitialize(const Deque<T>& Q) { Qptr = &Q; index = Q.size() – 1; }

  46. Implementing DequeIterator<T> (3) • Helper functions template <typename T> int DequeIterator<T>::valid() const { if (Qptr == 0) return 0; if (index >= Qptr->size()) return 0; return 1; } template <typename T> T& DequeIterator<T>::operator[] (size_t i) const { if (!Qptr) { // error } return Qptr->operator[](index + i); }

  47. Implementing DequeIterator<T> (4) • Helper functions template <typename T> T& DequeIterator<T>::retrieve() const { // check for validity return Qptr->operator[](index); } template <typename T> T& DequeIterator<T>::operator* () const { if (Qptr == 0) { // error } if (Qptr->size() == 0) { // error } return Qptr->operator[](index); }

  48. Implementing DequeIterator<T> (5) • Comparators template <typename T> int DequeIterator<T>::operator==(const DequeIterator<T>& I2) const { if (Qptr != I2.Qptr) return 0; if (index != I2.index) return 0; return 1; } template <typename T> int DequeIterator<T>::operator!=(const DequeIterator<T>& I2) const { return !(*this == I2); }

  49. Implementing DequeIterator<T> (6) • Assignment template <typename T> DequeIterator<T>& DequeIterator<T>::operator=(const DequeIterator<T> & I) { if (this != &I) { Qptr = I.Qptr; index = I.index; } return *this; }

  50. Implementing DequeIterator<T> (7) • Various operators template <typename T> DequeIterator<T>& DequeIterator<T>::operator++() { ++index; return *this; } template <typename T> DequeIterator<T> DequeIterator<T>::operator++(int) { DequeIterator<T> I(*this); operator ++(); return I; }

More Related