Upload
joylyn
View
29
Download
2
Tags:
Embed Size (px)
DESCRIPTION
Generic Positional Containers and Double-Ended Queues. Andy Wang Data Structures, Algorithms, and Generic Programming. Generic Positional Containers. A generic container C Stores elements by position vector[i] = ‘a’; list.insert(I, ‘a’); A template class for a proper type T - PowerPoint PPT Presentation
Citation preview
Generic Positional Containers and Double-Ended Queues
Andy WangData Structures,
Algorithms, and Generic Programming
Generic Positional Containers
A generic container C– Stores elements by position
vector[i] = ‘a’;list.insert(I, ‘a’);
– A template class for a proper type T– C<T> is a proper type– C<T> is capable of storing a number of T objs– C<T> supports an iterater class C<T>::Iterator
More on Generic pContainers
Organized and accessed by position– Can insert any T object at any position in C<T>– Can remove any T object at any position in C<T>– Can support
PushFront(), PopFront(), Front() PushBack(), PopBack(), Back()
Traditional Double-Ended Queue Class
Deque (pronounced “deck”) Deque operations
– Push/Pop at either end– Retrieve data from either end– Proper type
Traditional Double-Ended Queue Class (2)
Assumptions on element type T (proper type)– Constructor T() and destructor ~T()– Copy constructor– Assignment operator=
Specifying TDeque<T>
Traditional assumptions, plus O(1) average runtime, O(Size()) space
– PushFront(t), PopFront(), Front()– PushBack(t), PopBack(), Back()
O(1) time and space for iterator opeartions Random access iterators ([], pointer
arithmetics)
TDeque<T> Implementation Plan
Circular array– Protected array content of size content_size– Illusion: content[content_size] == content[0]
TDeque<T> D Illustrated
content_size = 8 D.Empty() == true
0 1 2 3 4 5 6 7
begin
end
content
TDeque<char> D Illustrated (2)
content_size = 8 D.PushBack(‘M’)
0 1 2 3 4 5 6 7
M
begin
end
content
TDeque<char> D Illustrated (3)
content_size = 8 D.PushBack(‘e’)
0 1 2 3 4 5 6 7
M e
begin
end
content
TDeque<char> D Illustrated (4)
content_size = 8 D.PushBack(‘r’)
0 1 2 3 4 5 6 7
M e r
begin
end
content
TDeque<char> D Illustrated (5)
content_size = 8 D.PushBack(‘r’)
0 1 2 3 4 5 6 7
M e r r
begin
end
content
TDeque<char> D Illustrated (6)
content_size = 8 D.PushBack(‘y’)
0 1 2 3 4 5 6 7
M e r r y
begin
end
content
TDeque<char> D Illustrated (7)
content_size = 8 D.PopFront() O(1)
0 1 2 3 4 5 6 7
e r r y
begin
end
content
TDeque<char> D Illustrated (8)
content_size = 8 D.PopFront()
0 1 2 3 4 5 6 7
r r y
begin
end
content
TDeque<char> D Illustrated (9)
content_size = 8 D.PushBack(‘G’)
0 1 2 3 4 5 6 7
r r y G
begin
end
content
TDeque<char> D Illustrated (10)
content_size = 8 D.PushBack(‘o’) D.Size() == (7 – 2 + 8) % 8
0 1 2 3 4 5 6 7
r r y G o
begin
end
content
TDeque<char> D Illustrated (11)
content_size = 8 D.PushBack(‘A’) D.Size() = (0 – 2 + 8) % 8
0 1 2 3 4 5 6 7
r r y G o A
begin
end
content
TDeque<char> D Illustrated (12)
content_size = 8 D.PushBack(‘r’)
0 1 2 3 4 5 6 7
r r r y G o A
begin
end
content
TDeque<char> D Illustrated (13)
D.Size() == content_size – 1 Return full or Double the capacity
0 1 2 3 4 5 6 7
r r r y G o A
begin
end
content
TDeque<T> Implementation Plan (2)
Relative Indexing– Protected integers begin, end– Element position relative to begin– Front element is content[begin]– Back element is content[end – 1]– Size is (end – begin + content_size) % content_size
TDeque<T> Implementation Plan (3)
Class Bracket Operator– Similar to TVector– Distinguished from TDeque Iterator bracket
operation
TDeque<T>::Iterator Implementation Plan
Public interface– Start with the public interface of TList<T>::Iterator– Add bracket operator– Add “pointer arithmetic”
Protected data– Pointer to a specific TDeque<T> object– A deque index value
Defining TDeque<T>
template <typename T>
class TDeque {
public:
typedef T value_type; // type definitions
typedef TDequeIterator<T> Iterator;
TDeque(); // constructors and deconstructor
TDeque(size_t, const T&);
TDeque(const TDeque<T>&);
~TDeque();
// display functions
void Display(ostream& os, char ofc = ‘\0’) const;
void Dump(ostream& os) const;
Defining TDeque<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 PushFront(const T&); // container write routines
int PopFront();
int PushBack(const T&);
int PopBack();
TDeque<T>& operator=(const TDeque<T>&);
Defining TDeque<T> (3)
friend class TDequeIterator<T>; // iterator support
Iterator Begin() const;
Iterator End() const;
protected:
T* content;
size_t content_size, begin, end;
};
Defining TDeque<T> (4)
// operator overloads (friend status not required)
template<class T>
ostream& operator<<(ostream& os, const TDeque<T>& a);
template<class T>
int operator==(const TDeque<T>&, const TDeque<T>&);
template<class T>
int operator!=(const TDeque<T>&, const TDeque<T>&);
Defining TDequeIterator<T>
template <typename T>
class TDequeIterator {
friend class TDeque<T>;
public:
typedef T value_type; // terminology support
TDequeIterator(); // constructors
TDequeIterator(const TDeque<T>& I);
TDequeIterator(const TDequeIterator<T>& I);
TDequeIterator(const size_t& i);
T& Retrieve() const; // return ptr to current Tval
int Valid() const; // cursor is valid element
Defining TDequeIterator<T> (2)
// various operators
int operator==(const TDequeIterator<T>& I2) const;
int operator!=(const TDequeIterator<T>& I2) const;
T& operator*() const; // return reference to current Tval
T& operator[] (size_t i) const; // return ref to Tval at index
TDequeIterator<T>& operator=(const TDequeIterator<T>& I);
TDequeIterator<T>& operator++(); // prefix
TDequeIterator<T> operator++(int); // postfix
TDequeIterator<T>& operator--(); // prefix
TDequeIterator<T> operator--(int); // postfix
Defining TDequeIterator<T> (3)
// pointer arithmeticlong operator-(const TDequeIterator<T>& I2) const;TDequeIterator<T>& operator+=(long n);TDequeIterator<T>& operator-=(long n);TDequeIterator<T> operator+(long n) const;TDequeIterator<T>& operator+=(int n);TDequeIterator<T>& operator-=(int n);TDequeIterator<T> operator+(int n) const;TDequeIterator<T>& operator+=(unsigned long n);TDequeIterator<T>& operator-=(unsigned long n);TDequeIterator<T> operator+(unsigned long n) const;TDequeIterator<T>& operator+=(unsigned int n);TDequeIterator<T>& operator-=(unsigned int n);TDequeIterator<T> operator+(unsigned int n) const;
Defining TDequeIterator<T> (3)
protected:
const TDeque<T>* Qptr;
size_t index;
};
Implementing TDeque<T>
Default constructortemplate <typename T>
TDeque<T>::TDeque() : content(0), begin(0), end(0), content_size(0) {
content = new T[default_content_size];
if (content == 0) {
// error
}
content_size = default_content_size;
}
Implementing TDeque<T> (2)
Copy constructortemplate <typename T>
TDeque<T>::TDeque(const TDeque<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];
}
}
Implementing TDeque<T> (3)
Read-only functionstemplate <typename T>
size_t TDeque<T>::Size() const {
return (end – begin + content_size) % content_size;
}
template <typename T>
T& TDeque<T>::operator[] (size_t i) const {
if (Size() <= i) {
// error
}
return (i + begin) % content_size;
}
Implementing TDeque<T> (4)
Display functionstemplate <typename T>void TDeque<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 TDeque<T>::Dump(ostream& os) const {
for (size_t j = 0; j < content_size; ++j) { // print }}
Implementing TDeque<T> (5)
Read-only operator overloadstemplate <typename T>
ostream operator<<(ostream& os, const TDeque<T>& Q) {
Q.Display(os);
return(os);
}
template <typename T>
int operator==(const TDeque<T>& Q1, const TDeque<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;
}
Implementing TDeque<T> (6)
Read-only operator overloadstemplate <typename T>
int operator!=(const TDeque<T>& Q1, const TDeque<T>& Q2) {
return !(Q1 == Q2);
}
Implementing TDeque<T> (7)
Read-only functionstemplate <typename T>
int TDeque<T>::Empty() const {
return begin == end;
}
template <typename T>
void TDeque<T>::Clear() {
begin = end = 0;
}
Implementing TDeque<T> (8)
Read-only functionstemplate <typename T>
T& TDeque<T>::Front() const {
// check for empty TDeque
return content[begin];
}
template <typename T>
T& TDeque<T>::Back() const {
// check for empty TDeque
return (end – 1 + content_size) % content_size;
}
Implementing TDeque<T> (9)
Iterator supporttemplate <typename T>
TDequeIterator<T> TDeque<T>::Begin() const {
TDeque<T>::Iterator I;
I.Qptr = this;
I.index = 0;
return I;
}
template <typename T>
TDequeIterator<T> TDeque<T>::End() const {
TDeque<T>::Iterator I;
I.Qptr = this;
I.index = Size();
return I;
}
Implementing TDeque<T> (10)
Assignmenttemplate <typename T>
TDeque<T>& TDeque<T>::operator=(const TDeque<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;
}
Implementing TDeque<T> (11)
PushBacktemplate <typename T>
int TDeque<T>::PushBack(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];
}
Implementing TDeque<T> (12)
PushBackif (begin < end) { begin += content_size; }
delete[] content;
content = newcontent;
content_size = newcontent_size;
}
content[end] = Tval;
end = (end + 1) % content_size;
return 1;
}
Implementing TDeque<T> (13)
PushFronttemplate <typename T>
int TDeque<T>::PushFront(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];
}
Implementing TDeque<T> (14)
PushFrontif (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;
}
Implementing TDeque<T> (15)
Pop routinestemplate <typename T>
int TDeque<T>::PopFront() {
if (begin == end) return 0;
begin = (begin + 1) % content_size;
return 1;
}
template <typename T>
int TDeque<T>::PopBack() {
if (begin == end) return 0;
end = (end – 1 + content_size) % content_size;
return 1;
}
Implementing TDequeIterator<T>
Constructorstemplate <typename T>
TDequeIterator<T>::TDequeIterator() : Qptr(0), index(0) { }
template <typename T>
TDequeIterator<T>::TDequeIterator(const TDeque<T>& Q) : Qptr(&Q), index(0) { }
template <typename T>
TDequeIterator<T>::TDequeIterator(const TDequeIterator<T>& I) : Qptr(I.Qptr), index(I.index) { }
Implementing TDequeIterator<T> (2)
Initialization routinestemplate <typename T>
void TDequeIterator<T>::Initialize(const TDeque<T>& Q) {
Qptr = &Q;
index = 0;
}
template <typename T>
void TDequeIterator<T>::rInitialize(const TDeque<T>& Q) {
Qptr = &Q;
index = Q.Size() – 1;
}
Implementing TDequeIterator<T> (3)
Helper functionstemplate <typename T>
int TDequeIterator<T>::Valid() const {
if (Qptr == 0) return 0;
if (index >= Qptr->Size()) return 0;
return 1;
}
template <typename T>
T& TDequeIterator<T>::operator[] (size_t i) const {
if (!Qptr) { // error }
return Qptr->operator[](index + i);
}
Implementing TDequeIterator<T> (4)
Helper functionstemplate <typename T>
T& TDequeIterator<T>::Retrieve() const {
// check for validity
return Qptr->operator[](index);
}
template <typename T>
T& TDequeIterator<T>::operator* () const {
if (Qptr == 0) { // error }
if (Qptr->Size() == 0) { // error }
return Qptr->operator[](index);
}
Implementing TDequeIterator<T> (5)
Comparatorstemplate <typename T>
int TDequeIterator<T>::operator==(const TDequeIterator<T>& I2) const {
if (Qptr != I2.Qptr) return 0;
if (index != I2.index) return 0;
return 1;
}
template <typename T>
int TDequeIterator<T>::operator!=(const TDequeIterator<T>& I2) const {
return !(*this == I2);
}
Implementing TDequeIterator<T> (6)
Assignmenttemplate <typename T>
TDequeIterator<T>& TDequeIterator<T>::operator=(const TDequeIterator<T> & I) {
if (this != &I) {
Qptr = I.Qptr;
index = I.index;
}
return *this;
}
Implementing TDequeIterator<T> (7)
Various operatorstemplate <typename T>
TDequeIterator<T>& TDequeIterator<T>::operator++() {
++index;
return *this;
}
template <typename T>
TDequeIterator<T> TDequeIterator<T>::operator++(int) {
TDequeIterator<T> I(*this);
operator ++();
return I;
}
Implementing TDequeIterator<T> (8)
Various operatorstemplate <typename T>
TDequeIterator<T>& TDequeIterator<T>::operator--() {
--index;
return *this;
}
template <typename T>
TDequeIterator<T> TDequeIterator<T>::operator--(int) {
TDequeIterator<T> I(*this);
operator --();
return I;
}
Implementing TDequeIterator<T> (9)
Various operatorstemplate <typename T>
long TDequeIterator<T>::operator-(const TDequeIterator<T>& I2) const {
return index – I2.index;
}
template <typename T>
TDequeIterator<T> TDequeIterator<T>::operator+(long n) const {
TDequeIterator<T> I(*this);
return I += n;
}
Implementing TDequeIterator<T> (10)
Various operatorstemplate <typename T>
TDequeIterator<T>& TDequeIterator<T>::operator+=(long n) {
index += n;
return *this;
}
template <typename T>
TDequeIterator<T>& TDequeIterator<T>::operator-=(long n) {
index -= n;
return *this;
}