Download Linked Lists, Stacks, and Queues

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Red–black tree wikipedia , lookup

Lattice model (finance) wikipedia , lookup

Quadtree wikipedia , lookup

Interval tree wikipedia , lookup

Binary search tree wikipedia , lookup

B-tree wikipedia , lookup

Linked list wikipedia , lookup

Transcript
Linked Lists, Stacks, and Queues
Linked Lists
 A linked list is a series of connected nodes allocated in the heap.
 A node is a structure variable or an object with two types of member variables:

A data part: one or more member variables appropriate to hold the data in the list, and

A next part: a pointer variable to hold the address of the next node in the list.
Examples of Nodes Declared as Structure Variables
1. Node to hold an integer value:
struct IntegerNode
{
int value;
IntegerNode *next;
};
//data part
// next part
2. Node to hold the information about a product represented by the following structure type:
struct
{
ProductInfo
int prodNum;
double unitPrice;
int quantity;
// to hold a product number
// to hold a product unit price
// to hold a product quantity
};
Can be defined by one of the following structures:
struct ProductNode1
{
int prodNum;
double unitPrice;
int quantity;
// to hold a product number
// to hold its unit price
// to hold its quantity
struct ProductNode2
{
ProductInfo product; // a product’s information
ProductNode2 *next; // address of next node
};
ProductNode1 *next; // address of next node
};
However, structure type ProductNode2 is more suitable than structure type ProductNode1 for lists
processing.
©2011 Gilbert Ndjatou
Page 221
Examples of Nodes Declared as Object Instances of a Class
a. Node to hold an integer value:
class IntegerNode
{
public:
int value;
IntegerNode *next;
};
//data part
// next part
b. Node to hold the information about a product represented by the following structure type:
struct
{
ProductInfo
int prodNum;
double unitPrice;
int quantity;
// to hold a product number
// to hold a product unit price
// to hold a product quantity
};
Can be defined by one of the following classes:
class ProductNode1
{
public:
int prodNum;
double unitPrice;
int quantity;
// to hold a product number
// to hold its unit price
// to hold its quantity
class ProductNode2
{
public:
ProductInfo product; // a product’s information
ProductNode2 *next; // address of next node
};
ProductNode1 *next; // address of next node
};
As in the case of structures, class ProductNode2 is more suitable than class ProductNode1 for lists
processing. In general, given a class AClass, we can define a class that can be used to create nodes with
its data members as the data part as follows:
class AClassNode
{
public:
AClass data;
AClassNode *next;
};
This class may also have constructors and other member functions.
©2011 Gilbert Ndjatou
Page 222
Exercise L1
1. Write the definition of a structure and the definition of a class that can be used to create a node with
a double precision value in its data part.
2. The information about a course is represented by the following structure:
struct CourseInfo
{
string courseNum;
int credit;
double gpv;
};
Write the definition of a structure and the definition of a class that can be used to create a node with
this information in its data part.
3. The information about a student is represented by the following structure:
struct StudentInfo
{
string firstName,
lastName;
int idNum;
double gpa;
};
Write the definition of a structure and the definition of a class that can be used to create a node with
this information in its data part.
4. Write the definition of a class that can be used to create nodes with the data part the data members of
the class Date that you defined in exercise O7.
5. Write the definition of a class that can be used to create nodes with the data part the data members of
the class Employee that you defined in exercise O9.
Creating a Linked List
 The nodes of a linked list are connected as follows:
1. There is a pointer variable (that is referred to as the head of the list) that holds the address of the
first node in the linked list. It holds NULL when the list is empty.
2.
The pointer variable next of the first node holds the address of the second node; that of the
second node holds the address of the third node; . . ., etc.
3. The pointer variable next of the last node holds NULL.
©2011 Gilbert Ndjatou
Page 223
Examples
a. Empty linked list:
NULL
List Head
b. Linked lists with three nodes:
Data
members
List Head
Data
members
Data
members
next
next
NULL
next
Example:
Address: 104
104
List Head
116
12
116
134
56
next
134
next
35
NULL
next
 You create an empty linked list as follows:
1. Define a pointer variable to hold the address of the first node in the linked list: head of the list.
2. Initialize that pointer variable to NULL.
Examples
1. Empty linked list to hold integer values:
IntegerNode *integerListHead ;
integerListHead = NULL;
2. Empty linked lists to hold information about products:
ProductNode1 *productListfirst1 = NULL;
ProductNode2 *productListfirst2 = NULL;
©2011 Gilbert Ndjatou
or
Page 224
Basic Operations on Linked Lists
 The following table lists some basic operations that can be performed on a linked list:
Operation
Inserting a node at the head of a
linked list.
Inserting a node after a given node in
the linked list.
Insert a node at the end (append) of a
linked list.
Removing the node from the head of
the linked list.
Removing the node after a given
node in the linked list.
Traversing a linked list (for example
to display the data in each node)
Destroying a linked list
 We implement the above operations by using a linked list of integer values.
Algorithm to Remove a Node from the Front of a Linked List
 The pointer variable discardptr is used to hold the address of the node to be removed from the list.
 The algorithm follows:
1. If the list is empty, then stop.
2. Set the pointer variable discardptr to the address of the first node in the list:
discardptr = head;
3. Set the head of the list to the node that follows the node to be removed:
head = discardptr -> next;
4. Release the first node: delete discardptr;
©2011 Gilbert Ndjatou
Page 225
Given the following linked list:
Address:
104
104
116
12
List Head
116
134
56
134
35
next
next
NULL
next
The list after the first node is removed:
Address:
116
116
List Head
134
56
134
next
35
NULL
next
 The function is defined as follows:
void removeFromFront( IntegerNode *head )
{
IntegerNode *discardptr;
if( head == NULL )
// cannot remove node from empty list: stop
{
cerror << endl << “cannot remove node from an empty linked list” << endl;
exit( 1 );
}
discardptr = head;
head = discardptr -> next;
delete discardptr;
}
Algorithm to Remove the Node after a Given Node from a Linked List
 The pointer variable discardptr is used to hold the address of the node to be removed from the list.
 The pointer variable afterMePtr hold the address of the node that precedes the node to be removed.
 The algorithm follows:
©2011 Gilbert Ndjatou
Page 226
1. If the address in the pointer variable afterMePtr is NULL or this node is the last node in the
list (afterMePtr -> next == NULL), then stop.
2. Set the pointer variable discardptr to the address of the node that follows the given node in
the list:
discardptr = afterMePtr -> next;
3. Connect the given node to the node that follows the node to be removed:
afterMePtr -> next = discardptr -> next;
4. Release the node: delete discardptr;
Given the following linked list:
Address:
104
104
116
12
List Head
116
134
56
134
next
next
35
NULL
next
The list after the second node is deleted: afterMePtr == 104
Address: 104
104
List Head
12
134
134
35
next
NULL
next
 The function is defined as follows:
void removeAfterMe( IntegerNode * afterMePtr )
{
IntegerNode *discardptr;
if( afterMePtr == NULL || afterMePtr -> next == NULL ) // There is no node to be removed
{
cerror << endl << “there is no node to be removed” << endl;
exit( 1 );
}
discardptr = afterMePtr -> next;
afterMePtr -> next = discardptr -> next;
delete discardptr;
}
©2011 Gilbert Ndjatou
Page 227
Algorithm to Insert a Node at the Front of a Linked List
 It is assumed that the data part of the node to be inserted is in the variable dataVal.
 The algorithm follows:
1. Create a new node and store its address in the pointer variable newptr:
IntegerNode *newptr = new IntegerNode;
2. Initialize the data part of this new node with the value in dataVal: newptr -> value = dataVal;
3. Connect this node to the previous first node: newptr -> next = head;
4. Make this node the first node: head = newptr;
Given the following linked list:
Address:
104
104
116
12
List Head
116
134
56
134
35
next
next
NULL
next
And the following node: newptr = 160
Address: 160
40
NULL
next
The list after this node is inserted at the front of the linked list:
Address:
104
160
116
12
List Head
116
next
134
56
134
next
35
NULL
next
Address: 160
40
104
Next
 The function is defined as follows:
©2011 Gilbert Ndjatou
Page 228
void insertAtFront(IntegerNode *head, int dataVal )
{
IntegerNode *newptr = new IntegerNode;
newptr -> value = dataVal;
newptr -> next = head;
head = newptr;
}
Algorithm to Insert a Node after a Given Node in a Linked List
 It is assumed that the address of the node that precedes the point of insertion is given and is stored in
the pointer variable afterMePtr.
 It is also assumed that the data part of the node to be inserted is in the variable dataVal.
 The algorithm follows:
1. If the pointer variable afterMePtr holds NULL, then stop.
2. Create a new node and store its address in the pointer variable newptr:
IntegerNode *newptr = new IntegerNode;
3. Initialize the data part of this new node with the value in dataVal: newptr -> value = dataVal;
4. Connect this node to the node that follows it in the list: newptr -> next = afterMePtr -> next;
5. Connect this node to the node that precedes it in the list: afterMePtr -> next = newptr;
Given the following linked list:
Address:
104
104
116
12
List Head
116
next
134
56
134
next
35
NULL
next
And the following node: newptr = 160
Address: 160
40
NULL
next
The list after the node is inserted after the second node: AfterMePtr == 116
©2011 Gilbert Ndjatou
Page 229
Address:
104
104
116
12
List Head
116
next
134
56
160
35
next
NULL
next
Address: 160
40
134
next
 The function is defined as follows:
void insertAfterMe(IntegerNode *afterMePtr, int dataVal )
{
if( afterMePtr == NULL )
// Invalid address: stop
{
cerror << endl << “Invalid address” << endl;
exit( 1 );
}
IntegerNode *newptr = new IntegerNode;
newptr -> value = dataVal;
newptr -> next = afterMePtr -> next;
afterMePtr -> next = newptr;
}
Algorithm to Output the Data Parts of the Nodes of a Linked List (List Traversal)
 The algorithm follows:
1. Set the current pointer variable currentptr to the address of the first node in the linked list:
currentptr = head;
2. As long as the address in the current pointer variable currentptr is not NULL, do the following:
a. output the data part of the current node :
currentptr -> value
b. Set the current pointer variable currentptr to the address of the next node:
currentptr = currentptr -> next;
 The function is defined as follows:
©2011 Gilbert Ndjatou
Page 230
void printList((ostream &outs, IntegerNode *head )
{
IntegerNode * currentptr;
currentptr = head;
while( currentptr != NULL )
{
outs << endl << currentptr -> value << endl;
currentptr = currentptr -> next;
}
Algorithm to Destroy a Linked List
 The algorithm follows:
1. Set the current pointer variable currentptr to the address in the first node in the linked list:
currentptr = head;
2. As long as the address in pointer variable currentptr is not NULL, do the following:
a. Save the address of the current node (so that it can be released later):
releaseptr = currentptr;
b. Set the current pointer variable currentptr to the address of the next node:
currentptr = currentptr -> next;
c. Release the node: delete releaseptr;
 The function is defined as follows:
void destroyList((IntegerNode *head )
{
IntegerNode * currentptr, // to hold the address of the current node
*releaseptr;
// to hold the address of the node to be removed
currentptr = head;
while( currentptr != NULL )
{
releaseptr = currentptr;
currentptr = currentptr -> next;
delete releaseptr;
}
©2011 Gilbert Ndjatou
Page 231
Algorithm to Append a Node to a Linked List
 It is also assumed that the data part of the node to be inserted is in the variable dataVal.
 The algorithm follows:
1. Create a new node and store its address in the pointer variable newptr:
node *newptr = new node;
2. Initialize the data part of this new node with the value in dataVal: newptr -> data = dataVal;
3. Initialize the next part of this node with NULL: newptr -> next = NULL;
4. If the list is empty (head == NULL), do the following:
a. make this node the first node in the list: head = newptr;
5. Otherwise, do the following:
a. Set the current pointer variable currentptr to the address of the first node in the list:
currentptr = head;
b. As long as the next part of the current node is not NULL (currentptr -> next != NULL), do
the following:
i.
Set the current pointer variable currentptr to the address of the next node:
currentptr = currentptr -> next;
c. Connect the last node of the list to the new node:
currentptr -> next = newptr;
 The function is defined as follows:
void appendNode((IntegerNode *head, int dataVal )
{
/*-----------------------create the new node to be inserted -----------------------------------*/
IntegerNode *newptr = new IntegerNode;
newptr -> value = dataVal;
newptr -> next = NULL;
if( head == NULL )
// Make this node the head of the list if the list is empty
head = newptr;
else
{
IntegerNode * currentptr;
currentptr = head;
while( currentptr -> next != NULL )
// find the last node in the list
currentptr = currentptr -> next;
currentptr -> next = newptr;
// insert the new node
}
©2011 Gilbert Ndjatou
Page 232
Algorithm for Searching a Linked List
 The value to be searched is in the variable target.
 The address of the node that contains the value that is being searched is returned if that value is in
the list; otherwise, NULL is returned.
 The algorithm follows:
1. Set the current node pointer variable currentPtr to the first node or the address in the pointer
variable head:
currentPtr = head;
2. As long as the data in the current node is not the searched value and the address in currentPtr is
not NULL, do the following:
( currentPtr != NULL && currentPtr -> value != target )
a. Make the next node the list the current node:
currentPtr = currentPtr -> next;
3. Return the address in the pointer variable currentPtr.
 The function is defined as follows:
IntergerNode * searchValue((IntegerNode *head, int target )
{
IntegerNode *currentPtr = head;
while( currentPtr != NULL && currentPtr -> value != target )
currentPtr = currentPtr -> next;
return( currentPtr );
}
©2011 Gilbert Ndjatou
Page 233
Exercise L2
For the following exercises, a node of the linked list is defined as follows:
struct Node
{
int data;
Node * next;
};
A. Pointer variable pt is defined as follows:
Node *pt;
Assuming that pt holds the address of a node, write the sequence of statement(s) to store into pointer
variable pt the address of the node that follows this node in the linked list.
B. Given the following linked list (with the address of the first node in the pointer variable head) and
the additional node, do the following:
Address:
128
128
140
78
List Head
140
next
154
23
154
next
15
NULL
next
Aditional node: newptr = 172
Address: 172
10
NULL
next
1.
a. Show the list after the new node is inserted at the front of the list.
b. Write the sequence of instructions to insert a new node at the front of the list.
2.
a. Show the list after the new node is inserted after the node with address 140.
b. Write the sequence of instructions to insert the node with address in pointer variable
newptr after the node with address in pointer variable predPtr.
3.
a. Show the list after the new node is inserted at the end of (appended) the list.
b. Write the sequence of instruction to append the node with address in pointer variable
newptr at the end of a non-empty list.
4.
a. Show the list after the first node is deleted.
b. Write the sequence of instructions to delete the first node from a non-empty list.
©2011 Gilbert Ndjatou
Page 234
5.
a. Show the list after the node that comes after the node with address 140 is removed from
the list.
b. Write the sequence of instructions to delete from a list the node that comes after the node
with address in pointer variable predPtr.
Exercise L3
An ordered linked list is a linked list such that the data values of the nodes are ordered either in
ascending order or in descending order.
1. Write the definition of the function Node *searchPosition( Node *first, int value) that receives as
arguments the head of an ordered linked list (in ascending order) and a value and does the following:
a. If the list is empty, it returns NULL.
b. If the list is not empty and the value received is less than the data value of the first node in the
list, it returns NULL.
c. Otherwise, it searches the linked list for the node that must precede the node with the value
received in the list and then returns its address.
2. Write the definition of the function void insertNode( Node *first, int value) that receives as
arguments the head of an ordered linked list (in ascending order) and a value and does the following:
a. It first creates a new node and places the value received in the data part of the new node.
b. It then calls function searchPosition( ) to search for the position of this new node in the list.
c. And finally, it inserts the new node in its position in the linked list. Note that the new node is
inserted at the front of the list if NULL is returned by function searchPosition( ).
3. Write the definition of the function int countNode( Node *first) that receives as argument the head of
a linked list and returns the number of nodes in that linked list.
Exercise L4
Write the definition of the function void reverseList( Node * & first ) that receives the head of a nonempty linked list and reverses its elements: That means the first node becomes the last node in the list
and the last node becomes the first. The function uses the reference parameter to return the address of
the head of the new list.
©2011 Gilbert Ndjatou
Page 235
Stacks
 A stack is a list of data designed such that data are retrieved in the reverse of the order in which they
are stored in the list.
 You can think of a stack as a hole in the ground: in order to remove an item from the hole, you must
first remove all the items on top of it. For this reason a stack is often called a last in/first out
(LIFO) data structure.
 In the following example, data are entered in the stack in the order: A B C D
D
C
B
A
 And they are retrieved in the order: D C B A
 A stack can be implemented by using an array, a dynamic array, or a linked list.
 In the implementation of a stack, a variable (referred to as the top of the stack) is used to hold the
position of the top of the stack: the location of the last data entered in the stack.
 The following are the basic operations on a stack:
Operation Description
push
top
pop
empty
Adds an element on top of the stack (if there is room in the stack);
otherwise, indicates that there is no room in the stack.
Returns the data at the top of the stack.
Returns the data at the top of the stack and then removes it from the
top of the stack.
Checks if a stack is empty: returns true if it is and false otherwise.
Implementing a Stack with an Array
 An array of size CAPACITY is used to hold the elements of a stack.
 Elements are entered in the stack at index 0, then 1, then 2, . . ., CAPACITY – 1.
 We indicate that a stack is empty by setting its top at position -1 (nothing is entered in the array).
©2011 Gilbert Ndjatou
Page 236
[5]
[5]
[4]
[4]
[3]
[3]
[2]
[2]
90
[1]
[1]
67
[0]
[0]
25
Empty stack: top = -1
top = 2
 The class is defined as follows:
©2011 Gilbert Ndjatou
Page 237
/*-------------------------------------------- Stack.h ---------------------------------------------------*/
#ifndef STACK_H
#define STACK_H
const int CAPACITY = 100;
typedef int dataType;
// maximum number of elements in the stack
// to be set before you compile the program
class Stack
{
public:
Stack( );
// constructor: create an empty stack
void push( dataType dataVal );
// add an element on top of the stack
void pop(dataType & dataVal ); // return the data at the top of the stack and then remove it
void top(dataType & dataVal ); // return the data at the top of the stack
bool isEmpty( );
// return true if the stack is empty and false otherwise
bool isFull( );
// return true if the stack is full and false otherwise
private:
dataType stackArray[ CAPACITY ];
int stackTop;
// The top of the stack
};
/*----------------------------------end of Stack.h -----------------------------------------------------------*/
/*----------------------------------------- Stack.cpp --------------------------------------------------------*/
#include <iostream>
#include “Stack.h”
/*------------------------------------ definition of the constructor ----------------------------------------*/
Stack :: Stack( )
{
stackTop = -1;
// empty stack
}
/*------------------------------------- member function top( ) ----------------------------------------------*/
/*-----------------use a reference variable to return the data at the top of the stack ------------------*/
void Stack :: top( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
}
©2011 Gilbert Ndjatou
Page 238
/*---------------------------------- member function pop( ) -------------------------------------------------*/
/*---- Use a reference variable to return the data at the top of the stack and then remove it -------*/
void Stack :: pop( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
stackTop -- ;
}
/*---------------------------------- member function push( ) ----------------------------------------------*/
void Stack :: push(dataType dataVal )
{
if( isFull( ) )
// the stack is full
{
cerr << endl << “Stack is full: new element cannot be added” << endl;
exit( 1 );
}
/*-----------------------------add the element to the top of the stack ----------------------------------*/
stackTop ++;
stackArray[ stackTop ] = dataVal;
}
/*--------------------------------------- member function isEmpty( )--------------------------------------*/
bool Stack :: isEmpty( )
{
return( stackTop == -1 );
}
/*------------------------------------- member function isFull( ) ---------------------------------------*/
bool Stack :: isFull( )
{
return( stackTop == CAPACITY - 1 );
}
©2011 Gilbert Ndjatou
Page 239
Implementing a Stack with a Dynamic Array
 One problem with implementing a stack with an array is that the size of the stack is fixed: one size
fits all. All the stack objects have the same size. With a dynamic array, the size of the array is set by
the constructor.
 Elements are entered in the stack in the same way as with static arrays: at index 0, then 1, then 2, . .
., capacity – 1.
 We indicate that a stack is empty in the same way that we did with static array: by setting its top at
position -1 (nothing is entered in the array).
 The definitions of the member functions push( ), pop( ), top( ), isEmpty( ), and isFull( ) are the
same as their definitions for the implementation of a stack with a static array. However, we must
provide the definitions of the copy constructor, the destructor, and the overloaded assignment
operator for the class.
 The class is defined as follows:
/*-------------------------------------------- DStack.h ---------------------------------------------------*/
#ifndef DSTACK_H
#define DTACK_H
typedef int dataType;
// to be set before you compile the program
class Stack
{
public:
Stack( int size = 10);
// create an empty stack: 10 is the default array size
Stack( const Stack & original );
// copy constructor
~Stack( );
// destructor
const Stack & operator =( const Stack & rightHandSide);
// overloaded assignment
void push( dataType dataVal );
// add an element on top of the stack
void pop(dataType & dataVal ); // return the data at the top of the stack and then remove it
void top(dataType & dataVal ); // return the data at the top of the stack
bool isEmpty( );
// return true if the stack is empty and false otherwise
bool isFull( );
// return true if the stack is full and false otherwise
private:
dataType *stackArray;
// dynamic array to hold the stack
int capacity;
// the size of the array
int stackTop;
// the top of the stack
};
/*----------------------------------end of DStack.h -----------------------------------------------------------*/
©2011 Gilbert Ndjatou
Page 240
/*----------------------------------------- DStack.cpp --------------------------------------------------------*/
#include <iostream>
#include “DStack.h”
/*------------------------------------------------------- constructor--------------------------------------------*/
Stack :: Stack( int size ) : capacity ( size )
{
stackArray = new dataType[ size ];
stackTop = -1;
}
/*-------------------------copy constructor Stack( const Stack & original ) -------------------------------*/
/* Initialize the elements of the new stack object with the elements of stack original
*/
Stack :: Stack( const Stack & original ) : capacity( original.capacity )
{
stackArray = new dataTye [ capacity ];
for ( int i = 0; i < capacity ; i ++ )
stackArray [ i ] = original.stackArray[ i ];
stackTop = original.stackTop;
}
/*-----------------------overloaded assignment operator------------------------------------------------------*/
/* use of const return to avoid left associativity: (A = B) = C
*/
/* do not copy a list into itself and if the two list do not have the same number of elements, deallocate
the original list and create another one with the same number of elements as the list being copied */
const Stack & Stack :: operator = ( const Stack & rightHandSide )
{
if ( this != & rightHandSide )
// copy only if the two lists are not the same
{
if ( capacity != rightHandSide.capacity )
{
delete [ ] stackArray;
// deallocate memory locations for the left side list
capacity = rightHandSide.capacity;
stackArray = new dataType [ capacity ];
}
for ( int i = 0; i < capacity ; i ++ )
stackArray [ i ] = original.stackArray [ i ];
stackTop = rightHandSide.stackTop;
}
return( *this);
}
©2011 Gilbert Ndjatou
Page 241
/*------------------------------------------------destructor ~Stack( )---------------------------------------*/
Stack :: ~Stack( )
{
delete [ ] stackArray;
}
/*---------------------------------- member function push( ) --------------------------------------------*/
void Stack :: push( dataType dataVal )
{
if( isFull( ) )
// the stack is full
{
cerr << endl << “Stack is full: new element cannot be added” << endl;
exit( 1 );
}
/*-----------------------------add the element at the top of the stack -------------------------------*/
stackTop ++;
stackArray[ stackTop ] = dataVal;
}
/*----------------------------------member function top( )------------------------------------------------*/
/*-----------------use a reference variable to return the data at the top of the stack ----------------*/
void Stack :: top( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
}
/*----------------------------- member function isEmpty( ) ----------------------------------------------*/
bool Stack :: isEmpty( )
{
return( stackTop == -1 );
}
©2011 Gilbert Ndjatou
Page 242
/*----------------------------------member function isFull( ) ----------- ------------------------------------*/
bool Stack :: isFull( )
{
return( stackTop == capacity - 1 );
}
/*---------------------------------- member function pop( ) -----------------------------------------------*/
/*---- Use a reference variable to return the data at the top of the stack and then remove it -----*/
void Stack :: pop( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
stackTop -- ;
}
/*---------------------------------------------end of DStack.cpp-----------------------------------------------*/
Exercise L5
1.
Suppose that the following operations are performed
on an empty stack s:
s.push( 5);
s.push(2);
s.push(10);
s.push(3);
Show the array and the value of variable stackTop
after the execution of these operations.
[4]
[3]
[2]
[1]
[0]
stackTop = -1
2.
©2011 Gilbert Ndjatou
Page 243
Suppose that the following operations are performed on
an empty stack s:
s.push( 5);
s.push(2);
s.pop(num);
s.push(10);
s.top(num);
s.push(3);
Show the array and the values of the variables num1, num2,
and stackTop after the execution of these operations.
[4]
[3]
[2]
[1]
[0]
stackTop = -1
3. Write the sequence of statements to create an empty stack of 10 elements using a dynamic array.
4. Write the sequence of statements to perform the push operation on a stack implemented as an array
that is not full. What is the condition for a stack implemented as an array to be full?
5. Write the sequence of statements to perform the pop and the top operations on a stack implemented
as an array that is not empty. What is the condition for a stack implemented as an array to be empty?
6. Write the sequence of instructions to read 10 integer values and to use a stack to print them in the
reverse of the order that they have been read in.
Implementing a Stack with a Linked List
 An array-based implementation of a stack imposes an upper limit on the size of the stack. That
means that a stack can become full and the user of this stack must be aware of this fact.
 A linked list implementation of a stack solves this problem by allowing a stack to grow without limit
and to shrink without wasting unused storage.
 With the linked list implementation, the top of the stack is implemented by the head of the list, and
a stack is empty when the head of the list holds NULL.
/*-------------------------------------------- LStack.h ---------------------------------------------------*/
#ifndef LSTACK_H
#define LSTACK_H
typedef int dataType;
// to be set before you compile the program
/*------------------------------ Definition of the linked list node ------------------------------------*/
struct StackNode
{
dataType data;
StackNode * next;
};
©2011 Gilbert Ndjatou
Page 244
class Stack
{
public:
Stack( );
// create an empty stack
Stack( const Stack & original );
// copy constructor
~Stack( );
// destructor
const Stack & operator =( const Stack & rightHandSide);
// overloaded assignment
void push( dataType dataVal );
// add an element on top of the stack
void pop(dataType & dataVal ); // return the data at the top of the stack and then remove it
void top(dataType & dataVal ); // return the data at the top of the stack
bool isEmpty( );
// return true if the stack is empty and false otherwise
private:
stackNode *stackTop;
// head of the linked list refers to the top of the stack
};
/*----------------------------------end of LStack.h -----------------------------------------------------------*/
/*----------------------------------------- LStack.cpp --------------------------------------------------------*/
#include <iostream>
#include “LStack.h”
/*------------------------------------------------------- constructor-------------------------------------------*/
Stack :: Stack( ) : stackTop( NULL )
{
}
/*--------------------------------destructor ~Stack( )--------------------------------------------------------*/
Stack :: ~Stack( )
{
StackNode *releasePtr;
// to hold the address of the node to be removed
while( StackTop != NULL )
{
releasePtr = StackTop;
StackTop = StackTop -> next;
delete releasePtr;
}
}
©2011 Gilbert Ndjatou
Page 245
/*-------------------------copy constructor Stack( const Stack & original ) ------------------------------*/
/* Create a new stack object and initialize its elements with the elements of the original stack */
Stack :: Stack( const Stack & original )
{
if( original.stackTop == NULL )
// original stack is empty
stackTop = NULL;
else
{
StackNode *from,
// hold the address of the current node in the original stack
*to;
// hold the address of the new node of the new stack
/* - create the first node of the new stack and copy the first node of the original stack to it -*/
to = new StackNode;
to -> data = original. stackTop -> data;
stackTop = to;
// copy the first node
/*----------------------------------- copy the rest of the nodes -------------------------------------------*/
from = original.stackTop -> next;
while( from != NULL )
{
to -> next = new StackNode;
// create a new node and connect it to the current node
to = to -> next;
// make the new node the current node
to -> data = from -> data
// copy the data to the current node
from = from -> next;
// make the next node in the original stack the current node
}
to -> next = NULL;
}
}
/*-----------------------overloaded assignment operator---------------------------------------------------------*/
/* use of const return to avoid left associativity: (A = B) = C
*/
/* do not copy a stack into itself. First destroy the left hand side stack and create another one with the
same number of nodes as the right hand side stack
*/
const Stack & Stack :: operator = ( const Stack & rightHandSide )
{
if ( this != & rightHandSide )
// copy only if the two stacks are not the same
{
this -> ~Stack( );
// destroy the left hand side stack
if ( rightHandSide.empty( ) )
// the right hand side stack is empty
stackTop = NULL;
else
©2011 Gilbert Ndjatou
Page 246
{
StackNode *from,
*to;
// hold the address of the current node in the right hand side stack
// hold the address of the new node of the left hand side stack
/* create the first node of the left hand side stack and copy the first node of the right hand
side stack to it */
to = new StackNode;
to -> data = rightHandSide. stackTop -> data;
stackTop = to;
// copy the first node
/*----------------------------------- copy the rest of the nodes -------------------------------------*/
from = rightHandSide.stackTop -> next;
while( from != NULL )
{
to -> next = new StackNode; // create a new node and connect it to the current node
to = to -> next;
// make the new node the current node
to -> data = from -> data
// copy the data to the current node
from = from -> next;// make the next node in the right hand side stack the current node
}
to -> next = NULL;
}
}
return( *this );
}
/*---------------------------------- member function push( ) -----------------------------------------------*/
void Stack :: push( dataType dataVal )
{
/*-----------------------------add the element to the top of the stack ----------------------------------*/
StackNode *newptr = new StackNode;
newptr -> data = dataVal;
newptr -> next = stackTop;
stackTop = newptr;
}
/*------------------------------- member function isEmpty(
bool Stack :: isEmpty( )
{
return( stackTop == NULL );
}
©2011 Gilbert Ndjatou
) ----------------------------------------*/
Page 247
/*---------------------------------- member function top( ) --------------------------------------------------*/
/*--------------------------------return the data at the top of the stack -------------------------------------*/
void Stack :: top(dataType & dataVal )
{
if( stackTop == NULL )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackTop -> data;
}
/*---------------------------------- member function pop -----------------------------------------------------*/
/*---------------return the data at the top of the stack and clear the top of the stack -----------------*/
void Stack :: pop(dataType & dataVal );
{
if( stackTop == NULL )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackTop -> data;
// return the data at the top of the stack
StackNode *discardptr;
// to hold the address of the node to be removed
discardptr = stackTop;
stackTop = stackTop -> next;
// set the top of the stack to the next node
delete discardptr;
}
/*---------------------------------------------end of LStack.cpp-------------------------------------------*/
Exercise L6
For the following exercises, assume that the structure used to define a node of a linked list is named
StackNode (with the data members data and next) and the head of the list (top of the stack) has its
address in pointer variable stackTop.
1. Write the sequence of statements to create an empty stack using a linked list.
2. Write the sequence of statements to perform the push operation on a stack (implemented as a linked
list) using the value in the variable dataVAl.
3. Write the sequence of statements to perform the pop and the top operations on a stack implemented
as a linked list that is not empty. The value retrieved front the stack will be stored in the variable
dataVal.
4. What is the condition for a stack implemented as a linked list to be empty?
©2011 Gilbert Ndjatou
Page 248
Queues
 A queue is a list of data designed such that data are retrieved in the order in which they are stored in
the list.
 You can think of a queue as a line in front of a cash register: the first person that arrives at the cash
register is the first to be served. For this reason a queue is often called a first in/first out (FIFO)
data structure.
 In the following example, data are entered in the queue in the order: A B C D
D
C
B
A
 And they are retrieved in the order: A B C D
 A queue can be implemented with an array, a dynamic array, or a linked list.
 In the implementation of a queue, a variable (referred to as the front/head of the queue) is used to
hold the position of the first element of the queue and a variable (referred to as the back/tail/rear of
the queue) is used to hold the position where the new element will be added in the queue.
 The following are the basic operations on a queue:
Operation
enqueue
front
dequeue
empty
Description
Adds an element to the back of the queue: Indicate if there is no
room in the queue for the new element.
Returns the data at the front of the queue.
Returns the data at the front of the queue and then removes it from
the front of the queue.
Checks if a queue is empty: returns true if it is and false otherwise.
Implementing a Queue with a Circular Array
 An array of size CAPACITY is used to hold the elements of a queue.
 Elements are entered and retrieved from the queue in the order, index 0, then 1, then 2, . . ., then
CAPACITY – 1, then 0, then 1 . . . etc.
©2011 Gilbert Ndjatou
Page 249
 A variable numElement is used to hold the number of elements entered in the queue:
0 <= numElement <= CAPACITY
 A queue is empty if numElement = 0.
 A queue is full if numElement = CAPACITY.
[4]
[4]
[3]
[3]
25
[2]
[2]
90
[1]
[1]
67
[0]
[0]
Empty queue: front = 0
back = 0
numElement = 0
front = 1
back = 4
numElement = 3
 The class is defined as follows:
/*-------------------------------------------- Queue.h ---------------------------------------------------*/
#ifndef QUEUE_H
#define QUEUE_H
const int CAPACITY = 100;
typedef int dataType;
// maximum number of elements in the queue
// to be set before you compile the program
class Queue
{
public:
Queue( );
// constructor: create an empty queue
void enqueue( dataType dataVal );
// add an element to the back of the queue
void dequeue(dataType & dataVal ); // return the data at the front of the queue and remove it
void front(dataType & dataVal );
// return the data at the front of the queue
bool isEmpty( );
// return true if the queue is empty and false otherwise
bool isFull( );
// return true if the queue is full and false otherwise
private:
dataType queueArray[ CAPACITY ];
int queueFront;
// the front of the queue
int queueBack;
// the back of the queue
int numElement;
// the number of elements in the queue
};
/*----------------------------------end of Queue.h -----------------------------------------------------------*/
©2011 Gilbert Ndjatou
Page 250
/*----------------------------------------- Queue.cpp --------------------------------------------------------*/
#include <iostream>
#include “Queue.h”
/*------------------------------------ definition of the constructor ----------------------------------------*/
Queue:: Queue( )
// empty queue
{
QueueFront = 0;
QueueBack = 0;
NumElement = 0;
}
/*----------------------------------definition of member function enqueue( )------------------------*/
void Queue :: enqueue( dataType dataVal )
{
if( isFull( ) )
// the queue is full
{
cerr << endl << “Queue is full: new element cannot be added” << endl;
exit( 1 );
}
/*-----------------------------add the element to the back of the queue---------------------------*/
queueArray[ queueBack ] = dataVal;
queueBack ++;
if( queueBack == CAPACITY )
queueBack = 0;
// queueBack = ( queueBack +1) % CAPACITY
numElement++;
}
/*----------------------------------definition of member function front( ) -----------------------------*/
/*-----------------use a reference variable to return the data at the front of the queue------------*/
void Queue :: front( dataType &dataVal )
{
if( isEmpty( ) )
// the queueis empty
{
cerr << endl << “Queue is empty” << endl;
exit( 1 );
}
dataVal = queueArray[ queueFront ];
}
©2011 Gilbert Ndjatou
Page 251
/*-------------------------definition of member function dequeue-- ------------------------------------*/
/*---- Use a reference variable to return the data at the front of the queue and then remove it -*/
void Queue :: dequeue( dataType &dataVal )
{
if( isEmpty( ) )
// the queue is empty
{
cerr << endl << “Queue is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ queueFront ];
queueFront ++ ;
if( queueFront == CAPACITY )
queueFront = 0;
// queueFront = (queueFront + 1) % CAPACITY
numElement--;
}
/*---------------------------------------------- member function isEmpty-------------------------------------*/
bool Queue:: isEmpty( )
{
return( numElement == 0 );
}
/*---------------------------------------------- member function isFull ---------------------------------------*/
bool Queue :: isFull( )
{
return( numElement == CAPACITY );
}
Implementing a Queue with a Circular Dynamic Array
 One problem with implementing a queue with an array is that the size of the queue is fixed: one size
fits all. All the queue objects have the same size. With a dynamic array, the size of the array is set
by the constructor.
 Elements are entered and retrieved from the queue in the same way as with static arrays: at index 0,
then 1, then 2, . . ., capacity – 1, then 0, then 1 . . .
 As with static arrays, a variable named numElement is used to hold the number of elements
entered in the queue:
0 <= numElement <= capacity
©2011 Gilbert Ndjatou
Page 252
 A queue is empty if numElement = 0.
 A queue is full if numElement = capacity.
 The definitions of the member functions enqueue( ), front( ), dequeue( ), isEmpty( ), and isFull( )
are the same as their definitions for the implementation of a queue with a static array. However, we
must provide the definitions of the copy constructor, the destructor, and the overloaded assignment
operator for the class.
 The definitions of the copy constructor, the destructor, and the overloaded assignment operator are
similar to those provided for the implementation of a stack with dynamic arrays.
 The class is defined as follows:
/*-------------------------------------------- DQueue.h ---------------------------------------------------*/
#ifndef DQUEUE_H
#define DQUEUE_H
typedef int dataType;
// to be set before you compile the program
class Queue
{
public:
Queue( int size = 10);
// create an empty queue: 10 is the default array size
Queue( const Queue & original ); // copy constructor
~Queue( );
// destructor
const Queue & operator =( const Queue & rightHandSide);
// overloaded assignment
void enqueue( dataType dataVal );
// add an element to the back of the queue
void dequeue(dataType & dataVal ); // return the data at the front of the queue and remove it
void front(dataType & dataVal );
// return the data at the front of the queue
bool isEmpty( );
// return true if the queue is empty and false otherwise
bool isFull( );
// return true if the queue is full and false otherwise
private:
dataType *queueArray;
// dynamic array to hold the queue
int capacity;
// the size of the array
int queueFront;
// the position of the front of the queue
int queueBack;
// the position of the back of the queue
int numElement;
// the number of element in the queue
};
/*-----------------------------------------end of DQueue.h --------------------------------------------------*/
©2011 Gilbert Ndjatou
Page 253
/*----------------------------------------- DQueue.cpp ------------------------------------------------------*/
#include <iostream>
#include “DQueue.h”
/*------------------------------------ definition of the constructor ----------------------------------------*/
Queue:: Queue( int size ) : capacity( size )
{
queueArray = new dataType[ size ];
QueueFront = 0;
QueueBack = 0;
NumElement = 0;
}
<Definitions of the other member functions>
/*-------------------------------- end of DQueue.cpp ---------------------------------------------------------*/
Exercise L7
Write the definitions of the copy constructor, the destructor, and the overloaded assignment operator of
the class Queue implemented with a dynamic circular array.
Exercise L8
1.
Suppose that the following operations are performed
on an empty queue q:
q.enqueue( 5);
q.enqueue(2);
q.enqueue( 9);
q.dequeue( num1);
q.enqueue(3);
q.front(num2);
q.enqueue(10);
q.dequeue(num3);
q.enqueue( 7);
q.enqueue(4);
q.dequeue( num4 );
[4]
[3]
[2]
[1]
[0]
QueueFront = 0
QueueBack = 0
NumElement = 0
Show he circular array, and the values of the variables
QueueFront, QueueBack, NumElement, num1, num2,
num3, and num4 after the execution of these operations.
©2011 Gilbert Ndjatou
Page 254
2.
Suppose that the following operations are performed on
the queue q shown on the right:
q.enqueue( 5);
q.enqueue(2);
q.enqueue( 9);
q.dequeue( num1);
q.dequeue(num2);
q.front(num3);
q.dequeue( num4);
q.dequeue(num5);
q.enqueue( 7);
q.dequeue( num6);
Show he circular array, and the values of the variables
QueueFront, QueueBack, NumElement, num1, num2, num3,
num4, num5, and num6 after the execution of these operations
[4]
[3]
15
[2]
20
[1]
[0]
QueueFront = 2
QueueBack = 4
NumElement = 2
3. Write the sequence of statements to enter (enqueue) the value in variable dataVal into a queue
(implemented with a circular array) that is not full.
4. Write the sequence of statements to remove (dequeue) one element from a queue (implemented with
a circular array) that is not empty and to store its value into the variable dataVal.
5. Write the definition of a member function dataType getlast(
element entered in the queue.
) that returns the value of the last
6. Write the definition of a member function void printQueue1( ) that outputs the values of the
elements of a queue (implemented with a circular array) in the order in which they are entered in the
queue (with a possible destruction of the queue).
7.
Write the definition of a member function void printQueue2( ) that outputs the values of the
elements of a queue (implemented with a circular array) in the order in which they are entered in the
queue (without destroying the queue).
Exercise L9
The service time of an individual that arrives at a cash register is the time it will take the cashier to
service that individual and the turn-around time of that individual is the sum of his service time and his
waiting time (that means the time that he must wait to get the service). Ten individuals have arrived at
the same time at the cash register and their service times are input in their order of arrival.
1. Write a code segment to define a queue that can hold at least 10 integer values, and to read these
service times into that queue.
2. Assuming that there is no interruption of service between an individual and the next one in the
queue, write a code segment to compute each individual’s turn-around time, and the average turnaround time.
©2011 Gilbert Ndjatou
Page 255
Implementing a Queue with a Linked List
 An array-based implementation of a queue imposes an upper limit on the size of the queue. That
means that a queue can become full and the user of this queue must be aware of this fact.
 A linked list implementation of a queue solves this problem by allowing a queue to grow without
limit and to shrink without wasting unused storage.
 With the linked list implementation, the head/front of the queue is implemented by the head of the
list, and a new pointer variable is defined to hold the address of the back/tail of a queue.
 A queue is empty when the head of the list holds NULL.
/*-------------------------------------------- LQueue.h ---------------------------------------------------*/
#ifndef LQUEUE_H
#define LQUEUE_H
typedef int dataType;
// to be set before you compile the program
/*------------------------------ Definition of the linked list node ------------------------------------*/
struct QueueNode
{
dataType data;
QueueNode * next;
};
class Queue
{
public:
Queue( );
// create an empty stack
Queue ( const Queue & original );
// copy constructor
~ Queue ( );
// destructor
const Queue & operator =( const Queue & rightHandSide); // overloaded assignment
void enqueue( dataType dataVal );
// add an element at the back of the queue
void dequeue(dataType & dataVal ); // return the data at the front of the queue and remove it
void front(dataType & dataVal );
// return the data at the front of the queue
bool isEmpty( );
// return true if the queue is empty and false otherwise
private:
queueNode *queueFront;
queueNode *queueBack;
// head of the linked list refers to the front of the queue
// the last node entered in the queue
};
/*----------------------------------end of LQueue.h -----------------------------------------------------------*/
©2011 Gilbert Ndjatou
Page 256
/*----------------------------------------- LQueue.cpp --------------------------------------------------------*/
#include <iostream>
#include “L Queue.h”
/*------------------------------------------------------- constructor-------------------------------------------*/
Queue :: Queue ( ) : queueFront( NULL ), queueBack( NULL )
{
}
/*--------------------------------destructor ~ Queue ( )----------------------------------------------------*/
Queue :: ~ Queue ( )
{
QueueNode *releasePtr;
// to hold the address of the node to be removed
while( queueFront != NULL )
{
releasePtr = queueFront;
queueFront = queueFont -> next;
delete releasePtr;
}
}
/*-------------------------copy constructor Queue( const Queue & original ) ------------------------------*/
/* Create a new queue object and initialize its elements with the elements of the original Queue */
Queue :: Queue ( const Queue & original )
{
if( original.queueFront == NULL )
// original queue is empty
queueFront = queueBack = NULL;
else
{
QueueNode *from,
// hold the address of the current node in the original queue
/* - create the first node of the new queue and copy the first node of the original queue to it -*/
queueFront = queueBack = new QueueNode;
queueFront -> data = original. queueFront -> data;
/*----------------------------------- copy the rest of the nodes -------------------------------------------*/
from = original.queueFront -> next;
while( from != NULL )
{
queueBack -> next = new QueueNode;
// create a new node and connect it to the current last node
©2011 Gilbert Ndjatou
Page 257
queueBack = queueBack -> next;
// make the new node the current last node
queueBack -> data = from -> data
// copy the data to the current last node
from = from -> next;
// make the next node in the original queue the current node
}
queueBack -> next = NULL;
}
}
/*-----------------------overloaded assignment operator---------------------------------------------------------*/
/* use of const return to avoid left associativity: (A = B) = C
*/
/* do not copy a queue into itself. First destroy the left hand side queue and create another one with the
same number of nodes as the right hand side queue
*/
const Queue & Queue :: operator = ( const Queue & rightHandSide )
{
if ( this != & rightHandSide )
// copy only if the two queues are not the same
{
this -> ~ Queue ( );
// destroy the left hand side queue
if ( rightHandSide.empty( ) )
// the right hand side queue is empty
queueFront = queueBack = NULL;
else
{
QueueNode *from,
// hold the address of the current node in the original queue
/* create the first node of the new queue and copy the first node of the original queue to it*/
queueFront = queueBack = new QueueNode;
queueFront -> data = rightHandSide. queueFront -> data;
/*-------------------------------- copy the rest of the nodes --------------------------------------*/
from = rightHandSide.queueFront -> next;
while( from != NULL )
{
queueBack -> next = new QueueNode;
// create a new node and connect it to the current last node
queueBack = queueBack -> next;
// make the new node the current last node
queueBack -> data = from -> data
// copy the data to the current last node
from = from -> next;
// make the next node in the original queue the current node
}
queueBack -> next = NULL;
}
}
return( *this );
}
©2011 Gilbert Ndjatou
Page 258
/*---------------------------------- member function enqueue( ) -----------------------------------------------*/
void Queue :: enqueue( dataType dataVal )
{
/*--------------------------------add the element to the back of the queue ----------------------------------*/
QueueNode *newptr = new QueueNode;
newptr -> data = dataVal;
newptr -> next = NULL;
if( queueFront != NULL)
// the queue is not empty
{
queueBack -> next = newptr;
// connect the last node to the new node
queueBack = newptr;
// make the new node the last node
}
else
queueFront = queueBack = newptr;
}
/*---------------------------------- member function front( ) --------------------------------------------------*/
/*--------------------------------return the data at the front of the queue -------------------------------------*/
void Queue :: front(dataType & dataVal )
{
if( queueFront == NULL )
// the queue is empty
{
cerr << endl << “Queue is empty” << endl;
exit( 1 );
}
dataVal = queueFront -> data;
}
/*---------------------------------- member function dequeue( )-----------------------------------------------*/
/*---------------return the data at the front of the queue and clear the front of the queue -----------------*/
void Queue :: dequeue(dataType & dataVal );
{
if( queueFront == NULL )
// the queue is empty
{
cerr << endl << “Queue is empty” << endl;
exit( 1 );
}
dataVal = queueFront -> data;
// return the data at the front of the queue
QueueNode *discardptr;
// to hold the address of the node to be removed
discardptr = queueFront;
queueFront = queueFront -> next;
// set the front of the queue to the next node
delete discardptr;
©2011 Gilbert Ndjatou
Page 259
if(queueFront == NULL )
queueBack = NULL;
}
/*------------------------------- member function isEmpty(
bool Queue :: isEmpty( )
{
return( queueFront == NULL );
}
) ----------------------------------------*/
/*---------------------------------------------end of LQueue.cpp-------------------------------------------*/
Exercise L10
For the following exercises, assume that the structure used to define a node of a linked list is named
QueueNode (with the data members data and next) and the head of the list (front of the queue) has its
address in pointer variable queueFront, and the tail of the queue has its address in the pointer variable
queueBack.
1. Write the sequence of statements to create an empty queue using a linked list.
2. Write the sequence of statements to perform the enqueue operation (with the value in variable
dataVal) on a queue (implemented with a linked list).
3. Write the sequence of statements to perform the dequeue operation on a queue (implemented with a
linked list) that is not empty and to store the value into the variable dataVal.
4. Write the definition of a member function dataType getlast( ) (of the class Queue implemented
with a linked list) that returns the value of the last element entered in the queue.
5. Write the definition of a member function void printQueue2( ) (of the class Queue implemented
with a linked list) that outputs the values of the elements of a queue in the order in which they are
entered in the queue (without destroying the queue).
©2011 Gilbert Ndjatou
Page 260
Class Templates
 In addition to function templates, you can define a class that can be applied to more than one data
type.
 A class that can be applied to more than one data type is referred to as a class template.
 You define a class template in the same way that you define a function template by preceding its
definition with the keyword template followed by a template parameter specified in angle brackets
as follows:
template < class T >
or
template < typename T >
Where:
T is the type parameter that represents the different data types that can be used in the
definition of the class.
 Member functions of a class template are defined as function templates.
 In the function prototypes and the definitions of the member functions and friend functions of a class
template, you follow the name of the class with < T >. Example: Stack< T >.
Example
The following is the class template that corresponds to the class Stack implemented with a static array:
/*-------------------------------------------- Stack.Th ---------------------------------------------------*/
#ifndef STACK_TH
#define STACK_TH
#include <iostream>
using namespace std;
const int CAPACITY = 100;
// maximum number of elements in the stack
template < class dataType >
class Stack
{
public:
Stack( );
// constructor: create an empty stack
void push( dataType dataVal );
// add an element on top of the stack
void pop(dataType & dataVal ); // return the data at the top of the stack and then remove it
void top(dataType & dataVal ); // return the data at the top of the stack
bool isEmpty( );
// return true if the stack is empty and false otherwise
bool isFull( );
// return true if the stack is full and false otherwise
private:
dataType stackArray[ CAPACITY ];
int stackTop;
// The top of the stack
};
©2011 Gilbert Ndjatou
Page 261
/*------------------------------------ definition of the constructor ----------------------------------------*/
template < class dataType >
Stack<dataType> :: Stack( )
{
stackTop = -1;
// empty stack
}
/*------------------------------------- member function top( ) ----------------------------------------------*/
/*-----------------use a reference variable to return the data at the top of the stack ------------------*/
template < class dataType >
void Stack<dataType> :: top( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
}
/*---------------------------------- member function pop( ) -------------------------------------------------*/
/*---- Use a reference variable to return the data at the top of the stack and then remove it -------*/
template < class dataType >
void Stack<dataType> :: pop( dataType &dataVal )
{
if( isEmpty( ) )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackArray[ stackTop ];
stackTop -- ;
}
©2011 Gilbert Ndjatou
Page 262
/*---------------------------------- member function push( ) ----------------------------------------------*/
template < class dataType >
void Stack<dataType>:: push(dataType dataVal )
{
if( isFull( ) )
// the stack is full
{
cerr << endl << “Stack is full: new element cannot be added” << endl;
exit( 1 );
}
/*-----------------------------add the element to the top of the stack ----------------------------------*/
stackTop ++;
stackArray[ stackTop ] = dataVal;
}
/*--------------------------------------- member function isEmpty( )--------------------------------------*/
template < class dataType >
bool Stack<dataType> :: isEmpty( )
{
return( stackTop == -1 );
}
/*------------------------------------- member function isFull( ) ---------------------------------------*/
template < class dataType >
bool Stack<dataType> :: isFull( )
{
return( stackTop == CAPACITY - 1 );
}
#endif
/*------------------------------------------------end of file Stack.Th---------------------------------------------*/
Using a Class Template to Define Objects
 You use a class template to define an object by specifying the data type to be used for the parameter
type.
Examples
Stack<int> stackOfIntegers;
Stack<char> stackOfCharacters, stch;
Stack<Employee> stackOfEmployees;
©2011 Gilbert Ndjatou
Page 263
Exercise L11
1. Write the class template that corresponds to the class Stack implemented with a Dynamic array.
2. Write the class template that corresponds to the class Queue implemented with a Dynamic array.
Class Template Implemented with a Linked List
 One way to define a class template implemented with a linked list is to write the structure (or the
class) definition of the linked list node in a private/public section of the class template definition.
Example
The following is the class template that corresponds to the class Stack implemented with a linked list:
/*-------------------------------------------- LStack.Th ---------------------------------------------------*/
#ifndef LSTACK_TH
#define LSTACK_TH
#include <iostream>
using namespace std;
template < class dataType >
class Stack
{
public:
Stack( );
// create an empty stack
Stack( const Stack<dataType> & original );
// copy constructor
~Stack( );
// destructor
const Stack & operator =( const Stack<dataType> & rightHandSide);
void push( dataType dataVal );
// add an element on top of the stack
void pop(dataType & dataVal ); // return the data at the top of the stack and then remove it
void top(dataType & dataVal ); // return the data at the top of the stack
bool isEmpty( );
// return true if the stack is empty and false otherwise
private:
/*----------------- Definition of the linked list node --------------------------------*/
struct StackNode
{
dataType data;
StackNode * next;
};
stackNode *stackTop;
// head of the linked list refers to the top of the stack
};
©2011 Gilbert Ndjatou
Page 264
/*------------------------------------------------------- constructor-------------------------------------------*/
template < class dataType >
Stack<dataType> :: Stack( ) : stackTop( NULL )
{
}
/*--------------------------------destructor ~Stack( )--------------------------------------------------------*/
template < class dataType >
Stack<dataType> :: ~Stack( )
{
StackNode *releasePtr;
// to hold the address of the node to be removed
while( StackTop != NULL )
{
releasePtr = StackTop;
StackTop = StackTop -> next;
delete releasePtr;
}
}
/*-------------------------copy constructor Stack( const Stack & original ) ------------------------------*/
/* Create a new stack object and initialize its elements with the elements of the original stack */
template < class dataType >
Stack<dataType> :: Stack( const Stack<dataType> & original )
{
if( original.stackTop == NULL )
// original stack is empty
stackTop = NULL;
else
{
StackNode *from,
// hold the address of the current node in the original stack
*to;
// hold the address of the new node of the new stack
/* - create the first node of the new stack and copy the first node of the original stack to it -*/
to = new StackNode;
to -> data = original. stackTop -> data;
stackTop = to;
// copy the first node
/*----------------------------------- copy the rest of the nodes -------------------------------------------*/
from = original.stackTop -> next;
while( from != NULL )
{
to -> next = new StackNode;
// create a new node and connect it to the current node
to = to -> next;
// make the new node the current node
to -> data = from -> data
// copy the data to the current node
©2011 Gilbert Ndjatou
Page 265
from = from -> next;
// make the next node in the original stack the current node
}
to -> next = NULL;
}
}
/*-----------------------overloaded assignment operator---------------------------------------------------------*/
/* use of const return to avoid left associativity: (A = B) = C
*/
/* do not copy a stack into itself. First destroy the left hand side stack and create another one with the
same number of nodes as the right hand side stack
*/
template < class dataType >
const Stack<dataType> & Stack<dataType> ::operator = (const Stack<dataType> &rightHandSide)
{
if ( this != & rightHandSide )
// copy only if the two stacks are not the same
{
this -> ~Stack( );
// destroy the left hand side stack
if ( rightHandSide.empty( ) )
// the right hand side stack is empty
stackTop = NULL;
else
{
StackNode *from,
// hold the address of the current node in the right hand side stack
*to;
// hold the address of the new node of the left hand side stack
/* create the first node of the left hand side stack and copy the first node of the right hand
side stack to it */
to = new StackNode;
to -> data = rightHandSide. stackTop -> data;
stackTop = to;
// copy the first node
/*----------------------------------- copy the rest of the nodes -------------------------------------*/
from = rightHandSide.stackTop -> next;
while( from != NULL )
{
to -> next = new StackNode; // create a new node and connect it to the current node
to = to -> next;
// make the new node the current node
to -> data = from -> data
// copy the data to the current node
from = from -> next;// make the next node in the right hand side stack the current node
}
to -> next = NULL;
}
}
return( *this );
}
©2011 Gilbert Ndjatou
Page 266
/*---------------------------------- member function push( ) -----------------------------------------------*/
template < class dataType >
void Stack<dataType>:: push( dataType dataVal )
{
/*-----------------------------add the element to the top of the stack ----------------------------------*/
StackNode *newptr = new StackNode;
newptr -> data = dataVal;
newptr -> next = stackTop;
stackTop = newptr;
}
/*------------------------------- member function isEmpty(
template < class dataType >
bool Stack<dataType> :: isEmpty( )
{
return( stackTop == NULL );
}
) ----------------------------------------*/
/*---------------------------------- member function top( ) --------------------------------------------------*/
/*--------------------------------return the data at the top of the stack -------------------------------------*/
template < class dataType >
void Stack<dataType> :: top(dataType & dataVal )
{
if( stackTop == NULL )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackTop -> data;
}
/*---------------------------------- member function pop -----------------------------------------------------*/
/*---------------return the data at the top of the stack and clear the top of the stack -----------------*/
template < class dataType >
void Stack<dataType> :: pop(dataType & dataVal );
{
if( stackTop == NULL )
// the stack is empty
{
cerr << endl << “Stack is empty” << endl;
exit( 1 );
}
dataVal = stackTop -> data;
// return the data at the top of the stack
StackNode *discardptr;
// to hold the address of the node to be removed
discardptr = stackTop;
stackTop = stackTop -> next;
// set the top of the stack to the next node
©2011 Gilbert Ndjatou
Page 267
delete discardptr;
}
#endif
/*---------------------------------------------end of LStack.Th-------------------------------------------*/
Exercise L12
Write the class template of the class Queue implemented with a linked list.
©2011 Gilbert Ndjatou
Page 268