Ответ 1
Когда мы говорим об абстракциях, мы должны попытаться определить основные аспекты того, что мы пытаемся реализовать. Обычно эти аспекты могут быть представлены как интерфейс.
Так как в С++, в отличие от других языков, таких как Java, у нас нет синтаксиса описания интерфейса, мы можем использовать чистые виртуальные классы.
В общем случае стек представляет собой структуру данных, следующую за структурой доступа LIFO, и не более того.
Несмотря на ограниченность объема памяти, я не вижу причин, по которым базовый стек должен иметь ограничение по размеру вначале. Более абстрактным способом мышления о пределе размера было бы проверить, принимает ли стек больше элементов или может предоставить и элемент через вызов pop
.
Итак, мы могли бы подумать о базовом интерфейсе стека следующим образом:
class Stack {
public:
virtual ~Stack()=0;
virtual Data& pop() throw (std::out_of_range) = 0;
virtual void push(Data&) throw (std::out_of_range) = 0;
virtual bool isPoppable() = 0;
virtual bool isPushable() = 0;
}
Теперь мы можем начать думать о реализациях. Простая реализация будет делать это с помощью массива:
class StackArray : public Stack {
private:
Data* mArray;
int mSize;
int mPointer;
StackArray(int size) : mSize(size), mPointer(0) {
mArray = new Data[mSize];
}
virtual ~StackArray() {
delete [] mArray;
}
public:
void push(Data& el) throw (std::out_of_range) {
if (!isPushable()) throw std::out_of_range("Cannot push to this stack");
mArray[mPointer++] = el;
}
Data& pop() throw (std::out_of_range) {
if (!isPopable()) throw std::out_of_range("Cannot pop from this stack");
return mArray[mPointer--];
}
bool isPushable() {
return mPointer < mSize;
}
bool isPoppable() {
return mPointer > 0;
}
}
Далее, мы могли бы подумать о стеке с привязкой к списку:
class DataNode {
private:
DataNode* next;
Data* data;
public: // trivial impl. ommited
bool hasNext();
DataNode* getNext();
Data* getData();
void setNext(DataNode* next);
void setData(Data* data);
}
class StackLinkedList : public Stack {
private:
DataNode* root;
public:
StackLinkedList():pointer(0) {}
virtual ~StackLinkedList() {}
void push(Data& el) throw (std::out_of_range) {
if (!isPushable()) throw std::out_of_range("Cannot push to this stack");
DataNode* n = new DataNode();
n->setData(&el);
DataNode* pointer = root;
if (root == NULL) {
pointer = n;
} else {
while (pointer->hasNext()) {
pointer = pointer->getNext();
}
pointer->setNext(n);
}
}
Data& pop() throw (std::out_of_range) {
if (!isPoppable()) throw std::out_of_range("Cannot pop from this stack");
DataNode* pointer = root, previous = NULL;
while (pointer->hasNext()) {
previous = pointer;
pointer = pointer->getNext();
}
Data* ret = pointer->getData();
delete pointer;
if (previous != NULL) {
previous->setNext(NULL);
}
return *ret;
}
bool isPushable() {
return true;
}
bool isPoppable() {
return root != NULL;
}
}