430 likes | 442 Views
Learn about the Queue ADT, array-based and list-based implementations, palindromes recognition, and the concept of templates in C++. Explore how to avoid redundancy with function templates and how to use ADTs with different item types.
E N D
Sample PMT online… • Browse http://www.cs.wmich.edu/gupta/teaching/cs1120/sumII05/PMT/2004_1/
Queue ADT • A queue is a FIFO: first in, first out
Application: Recognizing Palindromes • Palindrome is a string of characters that reads the same from left to right as it does from right to left • Madam, I’m Adam • A man, a plan, a canal, Panama
Pseudocode aQueue.createQueue(); aStack.createStack(); while (not end){ cin >> ch; aQueue.enqueue(ch); aStack.push(ch); } isPal = true; While(!aQueue.isEmpty() && isPal){ c1 = aQueue.getFront(); c2 = aStack.getTop(); if (c1==c2){ aQueue.dequeue(); aStack.pop(); } else { isPal = false; }
Array-Based Q Implementation class Queue { public: … private: QueueItem items[MAX_QUEUE]; int front, back; };
Problem with Array-based Implementation • Rightward shift • Queue is full even if it contains few items! • Solution: shift array items to the left • It would dominate the cost of implementation. • Any good idea?
Solution • View array as circular
How to Insert and Remove? • enqueue() • Move back index clockwise • dequeue() • Move front index clockwise
Special Cases • Queue has one item front==back • Queue is empty front is one item ahead (front == (back+1)%MAX_QUEUE)
Special Cases • When queue is full • front is one item ahead, again??
Distinguish Between Empty and Full • Keep a count of the number of items • Before enqueue, check if count == MAX_QUEUE • Before dequeue, check if count==0 class Queue { public: … private: QueueItem items[MAX]; int front, back; int count; };
Array-Based Implementation void Queue::Queue() :front(0), back(MAX-1), count(0) { } item Queue::getFront(){ if (isEmpty()) exit(0); else return items[front]; } bool Queue::isEmpty(){ return (count==0); }
Array-Based Implementation void Queue::enqueue(Item newItem) { if (count==MAX) exit(0); else { back = (back+1)%MAX; items[back] = newItem; ++count; } } void Queue::dequeue(){ if (isEmpty()) exit(0); else{ front =(front+1)%MAX; --count; } }
ADT List-Based Implementation class Queue { public: … private: List aList; };
ADT List-Based Implementation Queue::Queue (const Queue& Q) :aList(Q.aList){} bool Queue::isEmpty(){ return aList.isEmpty(); } void Queue::getFront(){ if (aList.isEmpty()) exit(0); return (aList.retrieve(1)); }
ADT List-Based Implementation void Queue::enqueue(){ aList.insert(aList.getLength()+1, newItem); } void Queue::dequeue(){ if (aList.isEmpty()) exit(0); aList.remove(1); }
The Items in ADTs class List { public: … private: Item items[MAX]; }; class Queue { public: … private: Item items[MAX]; }; • We have to substitute Item with concrete types class Stack { public: … private: Item items[MAX]; };
How to Use ADT with Different Item Types? • If we need only one integer list in our program • “typedef int Item;” • What if we need two lists: a list of real numbers and a list of characters? class RealList { private: float items[MAX]; }; class CharList { private: char items[MAX]; };
Similar Redundancy in Functions • Recall function swapValues void swapValues(int& var1, int& var2) { int temp; temp = var1; var1 = var2; var2 = temp; } • Applies only to variables of type int, but code would work for any types! void swapValues(char& var1, char& var2) { char temp; temp = var1; var1 = var2; var2 = temp; }
Avoid Redundancy by Templates • C++ templates • Allow very ‘general’ definitions for functionsand classes • Type names are ‘parameters’ instead ofactual types • Precise definition determined at run-time
Function Template Syntax • Allow swap values of any type variables template<class T> void swapValues(T& var1, T& var2) { T temp; temp = var1; var1 = var2; var2 = temp; } • First line called ‘template prefix’ • Tells compiler what’s coming is ‘template’ • And that T is a type parameter
Template Prefix • Recall:template<class T> • In this usage, ‘class’ means ‘type’, or‘classification’ • Can be confused with other ‘known’ useof word ‘class’! • C++ allows keyword ‘typename’ in place ofkeyword ‘class’ here • But most use ‘class’ anyway
Template Prefix 2 • Again:template<class T> • T can be replaced by any type • Predefined or user-defined (like a C++ classtype) • In function definition body: • T used like any other type • Note: can use other than ‘T’, but T is‘traditional’ usage
Calling a Function Template • Consider following call:swapValues(int1, int2); • C++ compiler ‘generates’ function definitionfor two int parameters using template • Likewise for all other types • Needn’t do anything ‘special’ in call • Required definition automatically generated
Another Function Template • Declaration: template<class T> void showStuff(int s1, T s2, T s3); • Definition: Template<class T> void showStuff(int s1, T s2, T s3) { cout << s1 << endl << s2 << endl << s3 << endl; }
showStuff Call • Consider function call:showStuff(2, 3.3, 4.4); • Compiler generates function definition • Replaces T with double • Since second parameter is type double • Displays:23.34.4
Multiple Type Parameters • Can have:template<class T1, class T2> • Not typical • Usually only need one ‘replaceable’ type • Cannot have ‘unused’ template parameters • Each must be ‘used’ in definition • Error otherwise!
Defining Templates Strategies • Develop function normally • Using actual data types • Completely debug ‘ordinary’ function • Then convert to template • Replace type names with type parameter asneeded • Advantages: • Easier to solve ‘concrete’ case • Deal with algorithm, not template syntax
Inappropriate Types in Templates • Can use any type in template for whichcode makes ‘sense’ • Code must behave in appropriate way • e.g.: swapValues() template function • Cannot use type for which assignmentoperator isn’t defined • int a[10], b[10];swapValues(a, b);
Class Templates • Can also ‘generalize’ classes • template<class T> can apply to class definition • All instances of ‘T’ in class definition replacedby type parameter • Just like for function templates! • Once template defined, can declareobjects of the class
Class Template Definition template <class T> class NewClass{ public: NewClass(); NewClass(T init); void setData(T nD); T getData(); private: T theData; };
Member Function Definitions template <class T> NewClass<T>::NewClass() {} template <class T> NewClass<T>::NewClass(T init): theData(init) {} template <class T> void NewClass<T>::setData(T nD){ theData = nD; } template <class T> T NewClass<T>::getData() { return theData; }
Member Function Definitions • Notice in member function definitions: • Each definition is itself a ‘template’ • Requires template prefix before eachdefinition • Class name before :: is ‘NewClass<T>’ • Not just ‘NewClass’ • But constructor name is just ‘NewClass’ • Destructor name is also just ‘~NewClass’
Class Template Usage int main(){ NewClass<int> a(5); NewClass<double> b; b.setData(1.5678); cout << a.getData(); };
Class Template • Be careful about what you do with objects of type T within the template class template <class T> void NewClass<T>::display() { cout << theData; }; • display() is correct if T is standard types such as int, char, string • What if T is user-defined?
Restrictions on Type Parameter • Only ‘reasonable’ types can be substitutedfor T • Consider: • Assignment operator must be ‘well-behaved’ • Copy constructor must also work • If T involves pointers, then destructor mustbe suitable! • Similar issues as function templates
Type Definitions • Can define new ‘class type name’ • To represent specialized class template name • Example:typedef NewClass<int> NewClassOfInt; • Name ‘NewClassOfInt’ now used to declareobjects of type NewClass<int>:NewClassOfInt n1, n2; • Name can also be used as parameter,or anywhere else type name allowed
Stack Revisited – dynamic array based implementation template<class T> class Stack { public: Stack(int s); ~Stack(){delete [] stackPtr}; bool push(const T&); bool pop(T&); private: int size; int top; T *stackPtr; bool isEmpty() const {return top==-1}; bool isFull()const {return top==size-1;} };
Stack Revisited template<class T> Stack<T>::Stack(int s) { size = s>0 ? s : 10; top = -1; stackPtr = new T[size]; } template<class T> bool Stack<T>::push(const T &pushValue) { if (!isFull()) { stackPtr[++top] = pushValue; return true; } return false; }
Stack Usage int main() { Stack<double> dStack(5); double f=1.1; while(dStack.push(f)) f+=1.1; while(dStack.pop(f)) cout << f <<endl; return 0; }