В данной статье я хотел бы рассказать о такой структуре данных как стек. Стек представляет собой одну из базовых структур данных и работает по системе LIFO (Last In First Out). Представить стек можно в виде стакана или стопки книг. Таким образом книга, положенная последней, будет взята первой и наоборот, первая положенная книга будет взята в самом конце.
Основные операции, выполняемые над стеком это вставка (Push) и удаление (Pop). Помимо этого я реализую не менее известные операции:
Показ верхнего элемента (Peek), проверку на пустоту (isEmpty), проверку на заполненность (isFull). Достаточно часто стек реализуется на базе массива, но может быть реализован и на базе других структур данных. Все примеры, приводимые в данной статье, будут написаны на C++
С чего хотелось бы начать? Давайте для начала создадим класс Stack и создадим конструктор, который будет инициализировать размер нашего массива
template <typename T>
class Stack
{
private:
T * m_stack;
size_t m_stackSize;
int m_top;
public:
Stack(size_t stackSize)
{
m_stack = new T[stackSize];
this->m_stackSize = stackSize;
m_top = -1;
}
~Stack() {}
}
Итак, наш стек создан, что уже неплохо. Теперь нам нужно научиться осуществлять операции Push() и Pop().
Для начала реализуем Push(). Суть данного метода заключается в том, чтобы положить элемент в стек и увеличить значение top. В случае, если стек заполнен, выдаем сообщение о переполнении стека
void Push(T key)
{
if (this->isFull())
{
cout << "Stack OverFlow" << endl;
}
else
{
m_stack[++m_top] = key;
}
}
Хорошо, со вставкой разобрались, пришла пора удаления. Удаление осуществляется тоже достаточно просто: мы просто достаем последний положенный элемент и уменьшаем наш top. В случае, если стек пуст, выдаем сообщение об ошибке.
T * Pop()
{
if (this->isEmpty())
{
std::cout << "Stack is Empty" << std::endl;
return nullptr;
}
else
{
return & m_stack[m_top--];
}
}
Итак, вставлять научились, удалять научились. Пришло время операции Peek. Данная операция настолько проста, что в комментариях не нуждается: мы просто смотрим на верхний элемент (если он есть, конечно).
T * Peek()
{
if (this->isEmpty())
{
std::cout << "Stack is Empty" << std::endl;
return nullptr;
}
else
{
return & m_stack[m_top];
}
}
Так же сразу предоставлю код isEmpty() и isFull()
bool isEmpty()
{
return (m_top == -1) ? true : false;
}
bool isFull()
{
return (m_top == this->m_stackSize - 1) ? true : false;
}
Ну вот и все, наш стек реализован и мы можем спокойно выпить чашечку кофе. В последующих статьях я продолжу рассматривать структуры данных, такие как очереди, списки, кучи и деревья. Буду искренне рад критике жителей Хабрахабра, потому что критика заставляет работать над собой. Спасибо за внимание!
P.S. Исходники моей вариации стека ниже:
template <typename T>
class Stack
{
private:
T * m_stack;
size_t m_stackSize;
int m_top;
public:
Stack(size_t stackSize)
{
m_stack = new T[stackSize];
this->m_stackSize = stackSize;
m_top = -1;
}
~Stack() {}
void Push(T key)
{
if (top == this->stackSize - 1)
{
std::cout << "Stack Overflow" << std::endl;
}
else
{
m_stack[++m_top] = key;
}
}
T * Pop()
{
if (this->isEmpty())
{
std::cout << "Stack is Empty" << std::endl;
return nullptr;
}
else
{
return & m_stack[m_top--];
}
}
T * Peek()
{
if(this->isEmpty())
{
std::cout << "Stack is Empty" << std::endl;
return nullptr;
}
else
{
return & m_stack[m_top];
}
}
bool isEmpty()
{
return (m_top == -1) ? true : false;
}
bool isFull()
{
return (m_top == this->m_stackSize - 1) ? true : false;
}
};
Комментарии (11)
lpre
10.09.2016 20:21+4T * m_stack; Stack(size_t stackSize) { m_stack = new T[stackSize]; } ~Stack() {}
А почему вы в конструкторе создаете m_stack, а в деструкторе не удаляете?
И почему вообще создаете динамически?
sophist
10.09.2016 20:35+5> return (m_top == -1)? true: false;
Логическое выражение — это такое же выражение, как и арифметическое, его можно не только использовать в условиях, но и присваивать, и возвращать из функций.
Ваша строчка эквивалентна следующей:
return m_top == -1;
lukdiman
10.09.2016 21:31-1А почему не расширяете размер массива когда вставляете элемент с индексом равным размеру массива?
ukhegg
10.09.2016 21:52+1Появились, конечно, некоторые замечания:
- Отсутствие проверки на 0 в конструкторе переданного параметра
- Передача неизменяемых параметров в методы(Push) в православном программированиии производится по const&
.До кучи еще бы добавить методы с перемещением параметровvoid Push(T const& arg){...}
void Push(T&& arg){...}
- Для Peek(...) логичнее и правильнее возвращать значение опять же по ссылке(T const& и T&)
T const& Peek() const {...} T& Peek(){...}
Тогда им никто не сможет зарядить пистолет и выстрелить в ногуdelete s.Peek();
- Методs isEmpty и isFull суть константные:
bool isEmpty() const {...} bool isFull() const {...}
- Как было сказано выше: а кто ответственен за удаление выделенной памяти?
- А как же копирующие, перемещающие конструкторы, операторы сравнения, присваивания?
ИМХО, почитали бы что-нибудь серьезнее учебника по C++. Не говорю про исходники Stl или Boost, там много лишней отвлекающей кросскомпиляторной материи, отвлекающей внимание.
dacentered
10.09.2016 23:30Так как Pop забирает значение из стека безвозвратно, лучше бы было передавать сам объект или его копию, а не ссылку на него. Это бы повысило локальность данных.
hose314
10.09.2016 23:30+1Если уж для самый маленьких, то хорошо бы написать зачем и где нужен этот атд. Сейчас образовательная нагрузка -> 0.
Onito
11.09.2016 00:39+2Действительно? Не в
Освободить память? Передавать в пул не по конст ссылке как замечено ниже? Это что вообще такое? Спрячьте в черновики быстрее мне стыдно за Хабр с такими постами
kalobyte
11.09.2016 07:22почему я не пошел в быдловуз?
потому что там вот так же дают какие-то данные, а зачем они нужны и что с ними делать — непонятно
про типы данных есть в любой книжке, лучше бы ты писал в формате:
— вот есть тип данных ааа
— его можно использовать там и тут
— вот код такого-то приложения с гитхаба, вот в этом месте используется тип ааа
— вот так это выглядит во время выполнения программы
— благодаря ему мы имеем профит ххх
— нельзя использовать тип ббб, потому что…
— можно использовать типы ццц и ддд, потому что…
DmitryKoterov
> this->isFull()
> this->m_stackSize
PHP detected. :)