View
222
Download
0
Category
Preview:
Citation preview
Stacks and Queues
• 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
Example
PseudocodeaQueue.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 itemfront==back
• Queue is emptyfront 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
item Queue::getFront(){ if (isEmpty()) exit(0); else return items[front];}
void Queue::Queue() :front(0), back(MAX-1), count(0) {}
bool Queue::isEmpty(){ return (count==0);}
Array-Based Implementation
void Queue::dequeue(){ if (isEmpty()) exit(0); else{ front =(front+1)%MAX; --count; }}
void Queue::enqueue(Item newItem){ if (count==MAX) exit(0); else { back = (back+1)%MAX; items[back] = newItem; ++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);}
Templates
The Items in ADTs
class List { public: …private: Item items[MAX];};
class Queue { public: …private: Item items[MAX];};
class Stack { public: …private: Item items[MAX];};
• We have to substitute Item with concrete types
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 swapValuesvoid 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 variablestemplate<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 assignment
operator 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 each
definition– 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 classtemplate <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
implementationtemplate<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 Revisitedtemplate<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 Usageint 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;}
Recommended