Lecture 3 - Queues)
Lecture 3 - Queues)
A Review
ADT's, a review
We've learned that it is often necessary to
develop new data types for our programming,
and we develop ADT's.
In C++, an ADT is constructed using the
class construct.
Classes contain public and private
information, and can have sections so labeled.
ADT's, a review
The public section contains the interface to
the ADT. It consists of a set of functions
called methods.
Two special types of methods exist and should
always be declared: constructors and
destructors.
Other methods provide the basic ability to
examine and manipulate objects of the new
Abstract Data Type.
ADT's, a review
The private section contains the basis for the
implementation the ADT. It usually contains
variables, constants and structures necessary for
the implementation.
This private information is only visible to and
accessible by the ADT itself; applications using
the ADT can't see this information or refer to it
in any way.
ADT's, a review
The class definition is placed in a header file
which we call the ADT definition header.
The ADT definition header should be included
by any source or header file that needs to use
the ADT in question.
The ADT definition header should also be
included by the ADT definition source file,
which implements all of the methods of the
ADT.
ADT's, a review
When creating a project that uses the ADT, the
ADT definition header should be placed in the
list of project header files. The ADT definition
source file should be placed in the list of project
source files.
ADT's, a review
Putting all of this together,
we arrive at the
following two files: IntStack.h and IntStack.cpp.
ADT's, a review
// FILE: INTSTACK.H – Stack of ints ADT definition
#ifndef _INTSTACK
#define _INTSTACK
class IntStack
{
public:
IntStack();
~IntStack();
bool is_empty() const;
bool is_full() const;
bool push (const int &value);
bool pop (int &value);
bool pop ();
int top() const;
private:
static const int MAX_SIZE = 10000;
int top_index;
int stack[MAX_SIZE];
};
#endif
ADT's, a review
// FILE: INTSTACK.CPP – Stack of ints ADT
implementation
#include "IntStack.h"
IntStack::IntStack()
{
top_index = -1;
}
IntStack::~IntStack()
{
}
bool IntStack::is_empty() const
{
return (top_index == -1);
}
bool IntStack::is_full() const
{
return (top_index == MAX_SIZE-1);
ADT's, a review
bool IntStack::push (const int &value)
{
bool result = false;
if (top_index < MAX_SIZE - 1)
{
top_index++;
stack[top_index]=value;
result = true;
}
return result;
}
bool IntStack::pop ()
{
bool result = false;
if (top_index != -1)
{
top_index--;
result = true;
}
return result;
}
ADT's, a review
bool IntStack::pop (int &value)
{
bool result = false;
if (top_index != -1)
{
value = stack[top_index];
top_index--;
result = true;
}
return result;
}
#ifndef _STACK_TEMPLATE
#define _STACK_TEMPLATE
#endif
Using Templates
Let's look at how we can use a template in an
application.
int main()
{
Stack<int> s;
int value;
???
{
public:
Queue();
~Queue();
bool is_empty() const;
bool is_full() const;
bool insert (const Type &value);
bool remove (Type &value);
bool remove ();
Type current () const; // value at head
// of queue
friend ostream &operator << <Type>(ostream &out,
const Queue<Type> &queue);
private:
friend functions
Introducing friend functions
instead of
MyType &add_operand (const MyType &operand)
operator overloading
and call by
my_number = x + y;
instead of
my_number = x.add_operand(y);
Queues
As with stacks, there are many ways to
implement a queue: e.g. - arrays, Vectors,
linked lists.
Array implementation: the traveling problem.
Unlike stacks, which have one movable end
(the top), queues have two movable ends (the
head and the tail)
Array implementation of Queues
private:
static const int MAX_SIZE = 100;
int head, tail;
int size;
Type queue[MAX_SIZE];
}
We maintain a size this time, for convenience (as we will see later)
Insertion is done by: tail++; queue[tail] = value;
removal is done by: value = queue[head]; head++;
1
tail
2
n-4
n-3
n-2
n-1
Array implementation of Queues
This is known as drift. The head and tail have
a tendency to move down the array and tail
reaches the end of the array, not allowing any
more insertions even though there’s room in
the area before the head.
Solution: Circular storage. Imagine that the
two ends of the array are wrapped around so
they meet. The “next” location after the last
one is the first one!!!
Array implementation of Queues
n-1 0
1
n-2
2
Circular Storage
Array implementation of Queues
template <class Type>
Queue<Type>::Queue()
{
size = 0;
head = 0; tail = -1;
}
if (success)
{
size++;
tail = (tail + 1) % MAX_SIZE;
queue[tail] = value;
}
return success;
}
Array implementation of Queues
template <class Type>
bool Queue<Type>::remove(Type &value)
{
bool success = !is_empty();
if (success)
{
size--;
value = queue[head];
head = (head + 1) % MAX_SIZE;
}
return success;
}
Array implementation of Queues
template <class Type>
bool Queue<Type>::remove()
{
bool success = !is_empty();
if (success)
{
size--;
head = (head + 1) % MAX_SIZE;
}
return success;
}
Array implementation of Queues
template <class BaseType>
BaseType Queue<BaseType>::current() const
{
return queue[head];
}
Array implementation of Queues
template <class Type>
ostream &operator << <Type>(ostream &out,
const Queue<Type> &x)
{
out << "head: " << x.head << ", tail: "
<< x.tail << ", size: " << x.size << endl;
for (int k = x.head, i = 0; i < x.size;
k = (k+1) % x.MAX_SIZE, i++)
out << k << ": " << x.queue[k] << endl;
return out;
}
Homework
Write a C++ program that reads a series of
numbers from cin. Upon completion, write
the non-negative values to cout in the reverse
order from how they came in. Then write the
negative values in the same order as they came
in.