I am learning about stacks, queues, lists & hash tables from the book Data Structures using C and C++ by Tanenbaum. I am also spending time to take in OOPs essentials, to ensure they sink in well, so that I don't learn by osmosis/need-be basis in the future, and there are no knowledge gaps.
The author of the book suggests, that an array based implementation of the ascending & descending priority queues can be realized using circular, ordered arrays. The author leaves the implementation of the routines insert()
and remove()
, as an exercise to the reader.
I built a PriorityQueue
class. My implementation of insert()
and remove()
routines is very cryptic. I produce the code verbatim for completeness(and not spamming).
Questions
- Could my implementation from an abstraction/encapsulation standpoint, be optimized?
- Would you in general call it good object oriented design?
Code
#ifndef PQueue_H
#define PQueue_H
#include <cmath>
#include <iostream>
const int maxsize = 5;
template <class T>
class PQueue
{
T items[maxsize];
int front, rear,n;
public:
PQueue(T val);
PQueue(const PQueue<T>& q);
~PQueue();
void insert(T x, int& overflow);
int search_position(T x);
T remove(int& underflow);
T first(int& underflow) const;
T last(int& underflow) const;
int size() const;
bool empty() const;
void print () const;
void increment(int& i);
void decrement(int& i);
};
template <class T>
PQueue<T>::PQueue(T val)
{
for (int i = 0; i < maxsize; i++)
items[i] = val;
front = rear = maxsize - 1;
n = 0;
}
template <class T>
PQueue<T>::PQueue(const PQueue<T>& q)
{
for (int i = 0; i < q.n; i++)
{
items[i] = q.items[i];
}
front = rear = maxsize - 1;
n = 0;
}
template <class T>
PQueue<T>::~PQueue() {};
template <class T>
int PQueue<T>::search_position(T x)
{
int low = front, high = rear;
int i;
if (empty()) {
return (rear+1)%maxsize;
}
for (i = (front+1)%maxsize; i != (rear+1)%maxsize; increment(i))
{
if (items[i] > x)
break;
}
return i;
}
template <class T>
void PQueue<T>::insert(T x, int& overflow)
{
overflow = 0;
if ((rear + 1) % maxsize == front)
{
overflow = 1;
return;
}
else
{
int index = search_position(x);
std::cout << "\nInserting item " << x << " at position " << index;
increment(rear);
//If index matches the updated value of rear,
//there must be nothing to shift.
if(index!=rear)
{
int i = rear - 1, j = rear;
i += maxsize; i %= maxsize;
j += maxsize; j %= maxsize;
do
{
//Shift all elements 1 position to
//the right in item[index...rear]
items[j] = items[i];
std::cout << "\nShifting item " << items[i] << " from index "
<< i << " to " << j;
decrement(i);
decrement(j);
} while (j != index);
}
n++;
items[index] = x;
}
}
template <class T>
T PQueue<T>::remove(int& underflow)
{
underflow = 0;
if (empty())
{
underflow = 1;
return -1;
}
else
{
increment(front);
std::cout << "\nRemoving item " << items[front] << " from the front";
n--;
return items[front];
}
}
template <class T>
T PQueue<T>::first(int& underflow) const
{
if (empty())
{
underflow = 1;
return -1;
}
else
{
return items[(front + 1) % maxsize];
}
}
template <class T>
T PQueue<T>::last(int& underflow) const
{
if (empty())
{
underflow = 1;
return -1;
}
else
{
return items[rear];
}
}
template <class T>
int PQueue<T>::size() const
{
return n;
}
template <class T>
bool PQueue<T>::empty() const
{
if (front == rear)
return true;
else
return false;
}
template <class T>
void PQueue<T>::print() const
{
std::cout << "\nQueue items : ";
for (int i = (front + 1) % maxsize; i != (rear+1)%maxsize; i=(++i)%maxsize)
{
std::cout << "items[" << i << "] = " << items[i] << "\t";
}
}
template <class T>
void PQueue<T>::increment(int& i)
{
++i;
i %= maxsize;
}
template <class T>
void PQueue<T>::decrement(int& i)
{
--i;
i += maxsize; i %= maxsize;
}
#endif // !PriorityQueue_H
insert()
andremove()
functions the only aspect of the code that is yours? \$\endgroup\$