Класс стека предоставляет интерфейс для очень специализированного контейнера. Стек - это контейнер LIFO, который имеет минимальное количество функций-членов, которые вы можете использовать для работы с данными, хранящимися в стеке. Есть несколько областей информатики и компьютерного программирования, в которых стеки играют заметную роль. В этой статье мы обсудим, как использовать стеки в программировании на C ++, и продемонстрируем некоторые приложения, в которых используются стеки.
Обзор стека
Стек - это контейнер, в который все данные входят и выходят из верхней части контейнера. Вы можете выполнять три основные операции со стеком: 1) поместить новые данные в стек; 2) вытолкнуть верхний элемент данных из стека; и 3) просмотреть верх стека.
Если вы хотите придумать следствие из реальной жизни, подумайте о подносах в кафетерии. Когда клиент входит в кафетерий и получает поднос, он снимает поднос с вершины стопки. Когда посудомоечная машина чистит лоток и кладет его обратно, он оказывается поверх стопки лотков. Когда вы смотрите на стопку лотков, вы можете полностью увидеть только верхний лоток.
Как я упоминал ранее, стек считается контейнером «последним вошел - первым ушел», потому что последний элемент, помещенный на вершину стека, является первым элементом, выталкиваемым из вершины стека.
Объявление стеков
Заголовочный файл для класса стека:
#include <stack>
Класс stack
является классом-шаблоном, поэтому вы должны предоставить тип данных с объявлением, как в этих примерах:
stack<int> numbers; stack<string> people; stack<double> ratios; stack<char> operators;
Вы не можете инициализировать стек с помощью списка инициализаторов, и вы не можете указать начальную емкость в качестве аргумента конструктора, как вы можете с другими контейнерами.
Добавление данных в стек и просмотр вершины стека
Есть только один способ добавить данные в стек - функция push
. Функция push
берет элемент и сохраняет его наверху стека. Верх стека также является единственным элементом, к которому вы можете получить доступ в стеке. В классе есть функция для проверки вершины стека - функция top
.
Вот короткая программа, которая помещает некоторые данные в стек, а затем исследует верхнюю часть стека:
#include <iostream> #include <stack> using namespace std; int main() { stack<int> numbers; numbers.push(2); numbers.push(4); numbers.push(8); cout << "top of stack: " << numbers.top() << endl; // 8 return 0; }
Результат этой программы:
top of stack: 8
Удаление данных из стека
Данные удаляются из стека функцией pop
. Эта функция может удалить только элемент наверху стека. Как я упоминал ранее, никакие другие элементы в стеке недоступны, кроме элемента наверху.
Вот пример извлечения данных из стека с проверкой вершины стека после каждого извлечения:
int main() { stack<int> numbers; numbers.push(2); numbers.push(4); numbers.push(8); cout << "top of stack: " << numbers.top() << endl; // top of stack: 8 numbers.pop(); cout << "top of stack: " << numbers.top() << endl; // top of stack: 4 numbers.pop(); cout << "top of stack: " << numbers.top() << endl; // top of stack: 2 numbers.pop(); cout << "top of stack: " << numbers.top() << endl; // this line does not execute return 0; }
Последний оператор cout
не выполняется, потому что я пытался вытолкнуть пустой стек. Вы можете использовать функцию empty
, которая позволяет узнать, пуст ли стек или в нем все еще есть данные. Давайте изменим приведенную выше программу, чтобы использовать функцию empty
:
int main() { stack<int> numbers; numbers.push(2); numbers.push(4); numbers.push(8); while (!numbers.empty()) { cout << "top of stack: " << numbers.top() << endl; numbers.pop(); } return 0; }
Еще одна функция, которую вы можете использовать, чтобы определить, когда стек пуст, - это функция size
. Эта функция возвращает количество элементов в стеке. Вот как с его помощью не выскакивать пустая стопка:
int main() { stack<int> numbers; numbers.push(2); numbers.push(4); numbers.push(8); while (numbers.size() > 0) { cout << "top of stack: " << numbers.top() << endl; numbers.pop(); } return 0; }
Некоторые приложения стека
Стеки можно использовать для обслуживания нескольких интересных алгоритмов и приложений. Вот несколько из них.
Преобразование десятичных чисел в двоичные
Первый алгоритм, который я расскажу, - это алгоритм преобразования числа с основанием 10 (десятичного) в число с основанием 2 (двоичное). Вот алгоритм, где n - десятичное число, а B - основание (2):
0. Начать с пустой стопкой.
1. Получите крайнюю правую цифру числа n на n% Б. Поместите результат в стек.
2. Заменить n на n / B.
3. Повторяйте шаги 1 и 2 до n = 0.
4. Извлеките и распечатайте цифры из стека, в результате чего получится двоичное число.
Вот программа, реализующая этот алгоритм:
int main() { stack<int> binDigits; int decNumber; cout << "Enter a decimal number: "; cin >> decNumber; int number = decNumber; const int BASE = 2; int digit; while (decNumber > 0) { digit = decNumber % BASE; binDigits.push(digit); decNumber /= BASE; } string binNumber = ""; while (!binDigits.empty()) { binNumber += to_string(binDigits.top()); binDigits.pop(); } cout << number << " is " << binNumber << " in binary." << endl; return 0; }
Вот один из запусков этой программы:
Enter a decimal number: 53 53 is 110101 in binary.
В поисках палиндромов
Слово является палиндромом, если его можно писать одинаково вперед и назад. Слова радар и гоночный автомобиль являются примерами палиндромов. Мы можем использовать стек, чтобы определить, является ли слово палиндромом, помещая каждую букву слова в стек. Затем мы можем сформировать обратное слово, вставив стек в другое слово, пока стек не станет пустым. Если исходное слово и слово, образованное из стопки, равны, то слово является палиндромом.
Вот программа, которая проверяет, является ли слово палиндромом:
int main() { stack<char> letters; string word; cout << "Enter a word to check: "; cin >> word; for (unsigned i = 0; i < word.size(); i++) { letters.push(word[i]); } string revWord = ""; while (!letters.empty()) { revWord += letters.top(); letters.pop(); } if (revWord == word) { cout << word << " is a palindrome." << endl; } else { cout << word << " is not a palindrome." << endl; } return 0; }
Вот несколько запусков программы:
Enter a word to check: radar radar is a palindrome. Enter a word to check: racecar racecar is a palindrome. Enter a word to check: railcar railcar is not a palindrome.
Арифметические операторы, которые мы привыкли писать, записываются в инфиксном формате, например: (9.0 / 5.0) * 100 + 32.0. Однако мы должны использовать круглые скобки, чтобы указать правильный порядок операций, если мы не можем напрямую полагаться на нормальный порядок операций. С другой стороны, выражения Postfix можно писать без скобок, и при этом сохраняется надлежащий порядок операций.
Давайте создадим простой преобразователь инфикса в постфикс, который работает с арифметическими операторами, не содержащими круглых скобок, например a + b * c. Для этого преобразователя мы будем помещать арифметические операторы в стек в зависимости от их приоритета и помещать идентификаторы в оператор постфикса.
Вот программа:
#include <iostream> #include <stack> using namespace std; int getPrecedence(char op) { if (op == '+' || op == '-') { return 1; } else if (op == '*' || op == '/') { return 2; } else if (op == '^') { return 3; } else { return 0; } } bool isOp(char ch) { if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^') { return true; } return false; } int main() { stack<char> s; string infix = "a+b*c"; string postfix = ""; char ch; for (unsigned i = 0; i < infix.size(); i++) { ch = infix[i]; if (isOp(ch)) { if (s.empty()) { s.push(ch); } else if (getPrecedence(ch) >= getPrecedence(s.top())) { s.push(ch); } } else { postfix += ch; } } if (!s.empty()) { while (!s.empty()) { postfix += s.top(); s.pop(); } } cout << infix << endl; cout << postfix << endl; return 0; }
Отличным расширением этой программы было бы добавление проверки скобок, чтобы вы могли преобразовывать даже более сложные выражения. Если вы сделаете это расширение, я хотел бы увидеть вашу программу.
Использование стеков
Я только что показал вам три примера использования стеков для решения задач программирования. В более технической информатике стеки используются для управления функциями (см. Стек вызовов), управления памятью (см. Выделение памяти на основе стека), а также в алгоритмах для поиска с возвратом (см. Отслеживание с возвратом) и для создания многих других алгоритмов. более эффективным.
Благодарим за прочтение этой статьи. Отправляйте комментарии и предложения по электронной почте.