56
Generic Positional Containers and Double-Ended Queues Andy Wang Data Structures, Algorithms, and Generic Programming

Generic Positional Containers and Double-Ended Queues

  • Upload
    joylyn

  • View
    29

  • Download
    2

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

Page 1: Generic Positional Containers and Double-Ended Queues

Generic Positional Containers and Double-Ended Queues

Andy WangData Structures,

Algorithms, and Generic Programming

Page 2: Generic Positional Containers and Double-Ended Queues

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

Page 3: Generic Positional Containers and Double-Ended Queues

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()

Page 4: Generic Positional Containers and Double-Ended Queues

Traditional Double-Ended Queue Class

Deque (pronounced “deck”) Deque operations

– Push/Pop at either end– Retrieve data from either end– Proper type

Page 5: Generic Positional Containers and Double-Ended Queues

Traditional Double-Ended Queue Class (2)

Assumptions on element type T (proper type)– Constructor T() and destructor ~T()– Copy constructor– Assignment operator=

Page 6: Generic Positional Containers and Double-Ended Queues

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)

Page 7: Generic Positional Containers and Double-Ended Queues

TDeque<T> Implementation Plan

Circular array– Protected array content of size content_size– Illusion: content[content_size] == content[0]

Page 8: Generic Positional Containers and Double-Ended Queues

TDeque<T> D Illustrated

content_size = 8 D.Empty() == true

0 1 2 3 4 5 6 7

begin

end

content

Page 9: Generic Positional Containers and Double-Ended Queues

TDeque<char> D Illustrated (2)

content_size = 8 D.PushBack(‘M’)

0 1 2 3 4 5 6 7

M

begin

end

content

Page 10: Generic Positional Containers and Double-Ended Queues

TDeque<char> D Illustrated (3)

content_size = 8 D.PushBack(‘e’)

0 1 2 3 4 5 6 7

M e

begin

end

content

Page 11: Generic Positional Containers and Double-Ended Queues

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

Page 12: Generic Positional Containers and Double-Ended Queues

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

Page 13: Generic Positional Containers and Double-Ended Queues

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

Page 14: Generic Positional Containers and Double-Ended Queues

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

Page 15: Generic Positional Containers and Double-Ended Queues

TDeque<char> D Illustrated (8)

content_size = 8 D.PopFront()

0 1 2 3 4 5 6 7

r r y

begin

end

content

Page 16: Generic Positional Containers and Double-Ended Queues

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

Page 17: Generic Positional Containers and Double-Ended Queues

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

Page 18: Generic Positional Containers and Double-Ended Queues

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

Page 19: Generic Positional Containers and Double-Ended Queues

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

Page 20: Generic Positional Containers and Double-Ended Queues

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

Page 21: Generic Positional Containers and Double-Ended Queues

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

Page 22: Generic Positional Containers and Double-Ended Queues

TDeque<T> Implementation Plan (3)

Class Bracket Operator– Similar to TVector– Distinguished from TDeque Iterator bracket

operation

Page 23: Generic Positional Containers and Double-Ended Queues

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

Page 24: Generic Positional Containers and Double-Ended Queues

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;

Page 25: Generic Positional Containers and Double-Ended Queues

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>&);

Page 26: Generic Positional Containers and Double-Ended Queues

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;

};

Page 27: Generic Positional Containers and Double-Ended Queues

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>&);

Page 28: Generic Positional Containers and Double-Ended Queues

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

Page 29: Generic Positional Containers and Double-Ended Queues

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

Page 30: Generic Positional Containers and Double-Ended Queues

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;

Page 31: Generic Positional Containers and Double-Ended Queues

Defining TDequeIterator<T> (3)

protected:

const TDeque<T>* Qptr;

size_t index;

};

Page 32: Generic Positional Containers and Double-Ended Queues

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;

}

Page 33: Generic Positional Containers and Double-Ended Queues

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];

}

}

Page 34: Generic Positional Containers and Double-Ended Queues

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;

}

Page 35: Generic Positional Containers and Double-Ended Queues

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 }}

Page 36: Generic Positional Containers and Double-Ended Queues

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;

}

Page 37: Generic Positional Containers and Double-Ended Queues

Implementing TDeque<T> (6)

Read-only operator overloadstemplate <typename T>

int operator!=(const TDeque<T>& Q1, const TDeque<T>& Q2) {

return !(Q1 == Q2);

}

Page 38: Generic Positional Containers and Double-Ended Queues

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;

}

Page 39: Generic Positional Containers and Double-Ended Queues

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;

}

Page 40: Generic Positional Containers and Double-Ended Queues

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;

}

Page 41: Generic Positional Containers and Double-Ended Queues

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;

}

Page 42: Generic Positional Containers and Double-Ended Queues

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];

}

Page 43: Generic Positional Containers and Double-Ended Queues

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;

}

Page 44: Generic Positional Containers and Double-Ended Queues

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];

}

Page 45: Generic Positional Containers and Double-Ended Queues

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;

}

Page 46: Generic Positional Containers and Double-Ended Queues

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;

}

Page 47: Generic Positional Containers and Double-Ended Queues

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) { }

Page 48: Generic Positional Containers and Double-Ended Queues

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;

}

Page 49: Generic Positional Containers and Double-Ended Queues

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);

}

Page 50: Generic Positional Containers and Double-Ended Queues

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);

}

Page 51: Generic Positional Containers and Double-Ended Queues

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);

}

Page 52: Generic Positional Containers and Double-Ended Queues

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;

}

Page 53: Generic Positional Containers and Double-Ended Queues

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;

}

Page 54: Generic Positional Containers and Double-Ended Queues

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;

}

Page 55: Generic Positional Containers and Double-Ended Queues

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;

}

Page 56: Generic Positional Containers and Double-Ended Queues

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;

}