No.
wrong prototype is wrong:
1 2 3 4
|
T &at( const int POSITION ) const; //return type must be const T&. Write 2 functions for it.
//See function prototype of std::deque http://www.cplusplus.com/reference/deque/deque/at/
void push_back( const T obj ); //should be const T&. Do you want to use copy ctor every time push_back/push_front an object?
void push_front( const T obj ); //should be const T&
|
deque/vector should have at least an int capacity. When push_back/push_front an object to container, only allocate a new array with double capacity when the current array is full (number of elements in the array == capacity)
You can implement a circular array for push_front method, or use many small arrays (somewhat like 2d array, idk... perhaps std::deque use this technique), or use 2 array, one acts as front array, one acts as back array (bad if pop_front too much and pop_back too little, vice versa), or use 1 array but insert at middle (consume lots of memory, bad)
Here's how circular array works
[ ] [ ] [ ] [ ] (: : null / npos) init
[:1:] [ ] [ ] [ ] push_back 1
[:1] [2:] [ ] [ ] push_back 2
[:1] [2] [3:] [ ] push_back 3
[ ] [:2] [3:] [ ] pop_front
[ ] [ ] [:3:] [ ] pop_front
[ ] [ ] [:3] [4:] push_back 4
[ ] [ ] [ ] [:4:] pop_front
[ ] [ ] [:5] [4:] push_front 5
[ ] [:6] [5] [4:] push_front 6
[ ] [:6] [5:] [ ] pop_back
[:7] [6] [5:] [ ] push_front 7
[7] [6] [5:] [:8] push_front 8 //:] [: => full
[8] [7] [6] [5:] [ ] [ ] [ ] [:9] push_front 9
...
[:1] front pointer/index current position
[0:] back pointer/index current position
Example:
My CircularQueue class (implement a queue using circular array, no C++11), it doesn't have push_front, pop_back, or at() method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
#ifndef CIRCULARQUEUE_H
#define CIRCULARQUEUE_H
#include <exception>
template <class T>
class CircularQueue
{
public:
class NoSuchElementException : public std::exception {
const char* what()const throw()
{ return "Queue is empty. Cannot access top element."; }
};
public:
static const size_t DEFAULT_CAPACITY;
CircularQueue() : cap(DEFAULT_CAPACITY), contents(new T[cap]),
front(0), count(0) { }
~CircularQueue() { delete [] contents; }
bool isEmpty()const { return !count; }
void enqueue(const T& val);
void dequeue();
T top()const;
private:
bool isFull()const { return count == cap; }
void doubleCapacity();
private:
size_t cap;
T* contents;
size_t front;
size_t count;
};
template <class T>
const size_t CircularQueue<T>::DEFAULT_CAPACITY = 8;
template <class T>
T CircularQueue<T>::top()const
{
if (isEmpty()) throw NoSuchElementException();
return contents[front];
}
template <class T>
void CircularQueue<T>::doubleCapacity()
{
cap <<= 1;
T* newContents = new T[cap];
for (size_t i = 0; i < count; ++i) //copy old contents to new contents. Since it goes around so must % cap
newContents[i] = contents[(front+i)%cap];
delete [] contents;
contents = newContents;
front = 0;
}
template <class T>
void CircularQueue<T>::enqueue(const T& val) //push_back equivalent
{
if (isFull()) doubleCapacity();
contents[(front + count++)%cap] = val; //only increment count, or back pointer
}
template <class T>
void CircularQueue<T>::dequeue() //pop_front equivalent
{
contents[front++] = T(); //optional, may save a little memory
if (front >= cap) front -= cap; //make sure front always < cap (+ speed for top())
--count;
}
#endif // CIRCULARQUEUE_H
|