2. Templates in C++
• Template function in C++ makes it
easier to reuse classes and functions.
• A template may be viewed as a
variable that can be instantiated to
any data type, irrespective of
whether this data type is a
fundamental C++ type or a user-
defined type.
3. Two min() Functions
int min(int a, int b) {
return a < b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
• The following program shows the weakness of
strongly-typed languages:
4. The Template Solution
template <class Type>
Type min(Type a, Type b) {
return a < b ? a : b;
}
main() {
// ok: int min(int, int);
min(10, 20);
// ok: double min(double, double);
min(10.0, 20.0);
}
5. Selection Sort Template
template <class KeyType>
void SelectionSort(KeyType *a, int n)
// sort the n KeyType a[0] to a[n-1] into nondecreasing order
{
for (int i = 0; i < n; i++)
{
int j = i;
// find smallest KeyType in a[i] to a[n-1]
for (int k = i+1; k < n; k++)
if (a[k] < a[j]) j = k;
// interchange
KeyType temp = a[i]; a[i] = a[j]; a[j] = temp;
}
}
float farray[100];
int intarray[200];
………..
SelectionSort(farray, 100);
SelectionSort(intarray, 200);
6. Selection Sort Template
(Cont.)
• Can we use the sort template for the
Rectangle class?
• Well, not directly. We’ll need to use
operator overloading to implement
“<” for Rectangle class.
7. Stack
• What is a stack? A stack is an
ordered list in which insertions and
deletions are made at one end called
the top.
• It is also called a Last-In-First-Out
(LIFO) list.
8. Stack (Cont.)
• Given a stack S = (a0, …, an-1), a0 is the bottom
element, an-1 is the top element, and ai is on top of
element ai-1, 0 < i < n.
a0
a1
a2
Push (Add)
a0
a1
a2
Pop (Delete)
a3
a3
9. Inserting and Deleting
elements in a stack
B
A
D
C
B
A
C
B
A
D
C
B
A
E
D
C
B
A
top
top
top
top
top
top
A
Push (A) Push (B) Push (C) Push (D) Push (E) POP( ) = E
10. System Stack
• process of subroutine calls
q r s t q r s t
Top/ CURRENT-ADDR
O.S proc. MAIN proc. A1 proc. A2 proc. A3
run MAIN call A1 call A2 call A3
q: r: s: t:
end
11. System Stack (cont.)
• Whenever a function is invoked, the program creates a
structure, referred to as an activation record or a stack
frame, and places it on top of the system stack.
return address
previous frame pointer fp
main return address
previous frame pointer
fp
main
return address
previous frame pointer
a1
local variables
fp: a pointer to current stack frame
System Stack before a1 is invoked System Stack after a1 is invoked
12. ADT 3.1 Abstract Data
Type Stack
template <class KeyType>
class Stack
{ // objects: A finite ordered list with zero or more elements
public:
Stack (int MaxStackSize = DefaultSize);
~Stack();
// Create an empty stack whose maximum size is MaxStackSize
bool IsFull();
// if number of elements in the stack is equal to the maximum size
// of the stack, return TRUE(1) else return FALSE(0)
bool IsEmpty();
// if number of elements in the stack is 0, return TRUE(1) else return FALSE(0)
13. ADT 3.1 Abstract Data
Type Stack (cont.)
KeyType& Top();
// Return top element of stack
void Push(const KeyType& item);
// if IsFull(), then StackFull(); else insert item into the top of the stack.
KeyType* Pop(KeyType& );
// if IsEmpty(), then StackEmpty() and return 0;
// else remove and return a pointer to the top element of the stack.
};
14. Implementation of Stack
by Array
• Implementation of stack ADT
– use an one-dim array stack[MaxSize]
– bottom element is stored in stack[0]
– top points to the top element
• initially, top=-1 for an empty stack
– data member declarations in class
template < class KeyType >
class stack
private:
int top;
KeyType *stack;
int MaxSize;
public:
......
a0
a1
a2
Array index 0 1 2 3 n-1
a0 a1 a2
an-1
an-1
15. Implementation of Stack
by Array (cont.)
• constructor definition
• member function IsFull()
template <class KeyType>
Stack<KeyType>::Stack (int MaxStackSize) : MaxSize (MaxStackSize)
{
stack = new KeyType[MaxSize];
top = -1;
}
template <class KeyType>
inline bool Stack<KeyType>::IsFull()
{
if (top == MaxSize-1) return TRUE;
else return FALSE;
}
16. Implementation of Stack
by Array (cont.)
• member function IsEmpty()
• member function Top()
template <class KeyType>
inline bool Stack<KeyType>::IsEmpty() { return top == -1;}
template <class KeyType>
inline KeyType& Stack<KeyType>::Top()
{
if (IsEmpty()) throw “Stack is empty”;
return stack[top];
}
17. Implementation of Stack
by Array (cont.)
• Push operation
• Pop operation
template <class KeyType>
KeyType* Stack<KeyType>::Pop(KeyType& x)
{ // Remove top element from stack.
if (IsEmpty()) StackEmpty(); return 0;
x = stack[top--];
return &x;
}
template <class KeyType>
void Stack<KeyType>::Push(const KeyType& x)
{ // add x to stack
if (IsFull()) StackFull();
else stack[++top] = x;
}
*StackFull() and StackEmpty() depend on the particular application
18. Queue
• A queue is an ordered list in which all
insertions take place at one end and
all deletions take place at the
opposite end. It is also known as
First-In-First-Out (FIFO) lists.
a0 a1 a2
an-1
front rear
19. Queue (cont.)
• Inserting A, B, C, D, E, then delete an element
f = queue front r = queue rear
A A B A B C A B C D A B C D E B C D E
f r f r f r f r f r f r
add add add add delete
20. ADT 3.2 Abstract Data
Type Queue
template <class KeyType>
class Queue
{
// objects: A finite ordered list with zero or more elements
public:
Queue(int MaxQueueSize = DefaultSize);
// Create an empty queue whose maximum size is MaxQueueSize
bool IsFull();
// if number of elements in the queue is equal to the maximum size of
// the queue, return TRUE(1); otherwise, return FALSE(0)
bool IsEmpty();
// if number of elements in the queue is equal to 0, return TRUE(1)
// else return FALSE(0)
21. ADT 3.2 Abstract Data
Type Queue (cont.)
KeyType& Front();
// Return the element at the front of the queue
KeyType& Rear();
// Return the element at the rear of the queue
void Add(const KeyType& item);
// if IsFull(), then QueueFull(); else insert item at rear of the queue
KeyType* Delete(KeyType&);
// if IsEmpty(), then QueueEmpty() and return 0;
// else remove the item at the front of the queue and return a pointer to it
};
22. ADT 3.2 Abstract Data
Type Queue (cont.)
• Implementation of Queue ADT
– use an one-dim array
– two variables
• front : one less than the position of the first
element
• rear : the position of the last element
– data member declaration in class
template <class KeyType>
class Queue
private:
int front, rear;
keyType *queue;
int MaxSize;
public:
......
23. Queue Manipulation Issue
• It’s intuitive to use array for
implementing a queue. However,
queue manipulations (add and/or
delete) will require elements in the
array to move. In the worse case, the
complexity is of O(MaxSize).
25. Implementation of Queue
• constructor definition
• member function IsFull()
template <class KeyType>
Queue<KeyType>::Queue (int MaxQueueSize) : MaxSize (MaxQueueSize)
{
queue = new KeyType[MaxSize];
front = rear = -1;
}
template <class KeyType>
inline bool Queue<KeyType>::IsFull()
{
if (rear == MaxSize-1) return TRUE;
else return FALSE;
}
26. Implementation of Queue
(cont.)
• member function IsEmpty()
template <class KeyType>
inline bool Queue<KeyType>::IsEmpty()
{
if (front == rear) return TRUE;
else return FALSE;
}
• member function Add()
template <class KeyType>
void Queue<KeyType>::Add(const KeyType &x)
{
if (isFull) {cout << “Queue overflow”; exit(1);}
else queue[++rear] = x;
}
27. Implementation of Queue
(cont.)
• member function Delete()
template <class KeyType>
KeyType Queue<KeyType>::Delete()
{
if (IsEmpty())
{
cout << “Queue underflow”;
exit(1);
}
int x = queue[++front];
return x;
}
28. Circular Queue
• To resolve the issue of moving elements in
the queue, circular queue assigns next
element to q[0] when rear == MaxSize – 1.
• Pointer front will always point one position
counterclockwise from the first element in
the queue.
• Queue is empty when front == rear. But it
is also true when queue is full. This will be
a problem.
30. Circular Queue (Cont.)
• To resolve the issue when front == rear on whether
the queue is full or empty, one way is to use only
MaxSize – 1 elements in the queue at any time.
• Each time when adding an item to the queue,
newrear is calculated before adding the item. If
newrear == front, then the queue is full.
• Another way to resolve the issue is using a flag to
keep track of last operation. The drawback of the
method is it tends to slow down Add and Delete
function.
31. Implementation of
Circular Queue (cont.)
• member function Front()
• member function Rear()
template <class KeyType>
inline KeyType& Queue<KeyType>::Front()
{
if (IsEmpty()) throw ”Queue is empty. No front element”;
return queue[(front + 1) % MaxSize];
}
template <class KeyType>
inline KeyType& Queue<KeyType>::Rear()
{
if (IsEmpty()) throw ”Queue is empty. No rear element”;
return queue[rear];
}
32. Implementation of
Circular Queue (cont.)
• member function Add()
template <class KeyType>
void Queue<KeyType>::Add(const KeyType& x)
// add x to the circular queue
{
int k = (rear+1) % MaxSize;
if (front == k) QueueFull();
else queue[rear=k] = x;
}
33. Implementation of
Circular Queue (cont.)
• member function Delete()
template <class KeyType>
KeyType* Queue<KeyType>::Delete(KeyType& x)
// remove front element from queue
{
if (front == rear) { QueueEmpty(); return 0;}
x = queue[(++front)%= MaxSize];
return &x;
}
34. Subtyping and Inheritance
in C++
• Inheritance is used to express subtype
relationships between two ADTs.
• If B inherits from A, then B IS-A A. Also,
A is more general than B.
– 白馬是馬; Toyota IS-A Car; Eagle IS-A Bird;
• C++ provides a mechanism to express the
IS-A relationship called “public
inheritance”
35. Inheritance
• A derived class inherits all the non-private
members (public or protected data and functions)
of the base class.
• Inherited members from public inheritance have
the same level of access in the derived class as
they did in the base class.
• The derived class can reuse the implementation of
a function in the base class or implement its own
function, with the exception of constructor and
destructor.
36. Class Inheritance Example
class Bag
{ public:
Bag (int MaxSize = DefaultSize); // constructor
virtual ~Bag(); // destructor
virtual bool IsFull(); // return TRUE if the bag is full; FALSE otherwise
virtual bool IsEmpty(); // return TRUE if the bag is empty; FALSE otherwise
virtual void Add(int); // insert element into bag
virtual int* Delete(int&); //delete element from bag
protected:
virtual void Full(); // action when bag is full
virtual void Empty(); // action when bag is empty
int *array;
int MaxSize; // size of array
int top; // highest position in array that contains an element
};
37. Class Inheritance
Example(Cont.)
class Stack : public Bag
{
public:
Stack(int MaxSize = DefaultSize); // constructor
~Stack(); // destructor
int* Delete(int&); // delete element from stack
};
38. Class Inheritance
Example(Cont.)
Bag::Bag (int max_size) : MaxSize(max_size)
{
if (MaxSize < 1) throw ”Capacity must be 0”;
array = new int[MaxSize];
top = -1;
}
Bag::~Bag() {delete [] array;}
int* Bag::Delete(int& x)
{ if (IsEmpty()) {Empty(); return 0; }
x = array[top--];
return &x;
}
39. Class Inheritance
Example(Cont.)
Stack::Stack (int MaxStackSize) : Bag(MaxStackSize) { }
// Constructor for Stack calls constructor for Bag
Stack::~Stack() { }
// Destructor for Bag is automatically called when Stack is destroyed.
// This ensures that array is deleted.
int* Stack::Delete(int& x)
{ if (IsEmpty()) {Empty(); return 0; }
x = array[top--];
return &x;
}
40. Class Inheritance Example
(Cont.)
Bag b(3); // uses Bag constructor to create array of size 3
Stack s(3); // uses Stack constructor to create array of size 3
b.Add(1); b.Add(2); b.Add(3);
// use Bag::Add. Bag::Add calls functions Bag::IsFull and Bag::Full
s.Add(1); s.Add(2); s.Add(3);
// Stack::Add not defined, so use Bag::Add. Bag::Add calls Bag::IsFull and Bag::Full
// because these have not been redefined in Stack
int x;
b.Delete(x); // uses Bag::Delete, which calls Bag::IsEmpty and Bag::Emtpy
s.Delete(x);
// uses Stack::Delete, which calls Bag::IsEmtpy and Bag::Emtpy because these
// have not been redefined in Stack.
41. How about Queue ADT?
• The Queue ADT can also be a subtype of Bag. It
is more specialized than Bag because it requires
that elements be deleted in first-in first-out
order. Therefore, Queue can also be represented
as a derived class of Bag.
• However, there’s less similarity between the
implementations of Bag and Queue than there is
between Bag and Stack.
– Because Queue requires the data members front and rear
and the circular representation is different from that
of Bag
44. The Maze Problem (Cont.)
• Stack is used in solving the maze
problem for storing the coordinates
and direction.
• Use of another mp array to mark
any position that has been visited
before.
45. Evaluation of Expressions
• One of the challenges for higher-level
programming languages is to generate machine-
language instructions to evaluate an arithmetic
expression.
• X = A / B – C + D * E – A * C may have several
meanings.
• Still a formidable task to generate a correct
instruction sequence.
• Expression = {operands, operators, delimiters}
• Operators = {unary, binary, …}
46. Evaluation Expression in C++
• When evaluating
operations of the
same priorities, it
follows the
direction from left
to right.
Priority Operator
1 Unary minus, !
2 *, /, %
3 +, -
4 <, <=, >=, >
5 ==, !=
6 &&
7 ||
47. Parentheses Matching
• (((a+b)*c+d-e)/(f+g)-(h+j)*(k-l))/(m-n)
– Output pairs (u,v) such that the left parenthesis at
position u is matched with the right parenthesis at v.
– (2,6) (1,13) (15,19) (21,25) (27,31) (0,32) (34,38)
• (a+b))*((c+d)
– (0,4)
– right parenthesis at 5 has no matching left parenthesis
– (8,12)
– left parenthesis at 7 has no matching right parenthesis
48. Parentheses Matching
• scan expression from left to right
• when a left parenthesis is
encountered, add its position to the
stack
• when a right parenthesis is
encountered, remove matching
position from stack
54. Postfix Notation
• Expressions are converted into Postfix notation
before compiler can accept and process them.
X = A/B – C + D * E – A * C
Infix A/B–C+D*E–A*C
Postfix => AB/C-DE*+AC*-
Operation Postfix
T1 = A / B T1C-DE*+AC*-
T2 = T1 - C T2 DE*+AC*-
T3 = D * E T2T3+AC*-
T4 = T2 + T3 T4AC*-
T5 = A * C T4 T5 -
T6 = T4 - T5 T6
no need for parentheses
and priority of the operators
if using postfix notation!
55. Infix to Postfix: e.g. 1
• A + B * C ABC * +
next token stack output
none empty none
A empty A
+ + A
B + AB
* +* AB
C +* ABC
done + ABC*
done empty ABC*+
56. Infix to Postfix: e.g. 2
• A * (B + C) * D ABC+*D*
next token stack output
none empty none
A empty A
* * A
( *( A
B *( AB
+ *(+ AB
C *(+ ABC
) * ABC+
* * ABC+*
D * ABC+*D
done empty ABC+*D*
57. Priority-based Scheme for
stacking and unstacking
• Two functions: isp (in-stack priority), icp
(in-coming priority)
• isp(‘)’) = 8, icp(‘)’) = 0, isp(‘#’) = 8
(why?)
• Golden rule: Operators are taken out of
the stack as long as their in-stack priority
is numerically less than or equal to the in-
coming priority of the new operator.
58. Infix to Postfix:
Algorithm
void postfix (expression e)
// Output the postfix form of the infix expression e. NextTokne and stack
// are as in function eval (Program 3.18). It is assumed that the last to
// token in e is ‘#’. Also, ‘#’ is used at the bottom of the stack
{
Stack<token> stack; // initialize stack
token y;
stack.Push(‘#’);
for (token x=NextToken(e) ; x!=‘#’ ; x=NextToken(e) )
{
if (x is an operand) cout << x;
else if (x == ‘)’) // unstack until ‘(‘
for (y=*stack.Top(y) ; y!= ‘(‘ ; y=*stack.Pop(y) ) cout << y;
59. Infix to Postfix:
Algorithm (cont.)
else { // x is an operator
for (y=*stack.Pop(y) ; isp(y) <= icp(x) ; y=*stack.Pop(y)) cout <<y;
stack.Push(y); // restack the last y that ws unstacked
stack.Push(x);
}
}
// end of expression; empty stack
while (!stack.IsEmpty()) cout << *stack.Pop(y);
cout << endl;
} // end of postfix
60. Multiple Stacks and Queues
• Two stacks:
• How about more than two stacks (n)?
– Memory is divided into n segments
• The initial division of these segments may be done
in proportion to expected sizes of these stacks if
these are known
• All stacks are empty and divided into roughly equal
segments
Stack A Stack B
0 1 2 3 4 m-1
m-2
m-3
m-4