10. Стек. Класс Stack<T>. Правильная скобочная последовательность.
1. Стек
Возвращаемся к структурам данных.
Еще одна очень полезная в определенном классе программ структура – стек.
Стек (англ. stack — стопка) — абстрактный тип данных, представляющий собой список элементов, организованных по принципу LIFO («последним пришёл — первым вышел»).
Достаточно полное определение, но возможно для новичков оно будет немного трудным для понимания.
Поэтому первое, на чем бы я хотел заострить внимание, это представление стека в виде вещей из жизни. Первой на ум мне пришла интерпретация в виде стопки книг, где верхняя книга — это вершина.
На самом деле стек можно представить в виде стопки любых предметов будь то стопка листов, тетрадей, рубашек и тому подобное, но правильнее представить стек в виде узкого высокого стакана, в который можно помещать и доставать только по одному предмету.
Итак, из чего же состоит стек?
Стек состоит из ячеек, которые представлены в виде структуры, содержащей какие-либо данные и указатель типа данной структуры на следующий элемент.
На данной картинке схематично изображен стек. Блок вида «Данные/*next» и есть наша ячейка. *next, как мы видим, указывает на следующий элемент, другими словами указатель *next хранит адрес следующей ячейки. Указатель *TOP указывает на вершину стек, то есть хранит её адрес.
Класс Stack<T> представляет коллекцию, которая использует алгоритм LIFO ("последний вошел - первый вышел"). При такой организации каждый следующий добавленный элемент помещается поверх предыдущего. Извлечение из коллекции происходит в обратном порядке - извлекается тот элемент, который находится выше всех в стеке.
Иначе говоря, стек имеет вершину, которую образует последний добавленный элемент. При добавлении новый элемент помещается поверх вершины стека и образует новую вершину. При удалении удаляется элемент из вершины стека, а предыдущий элемент образует новую вершину.
В классе Stack можно выделить основные методы и свойства, которые позволяют управлять элементами:
- Push: добавляет элемент в стек на первое место.
- Pop: извлекает и возвращает первый элемент из стека. Если стек пуст, генерируется исключение типа InvalidOperationException.
- Peek: просто возвращает первый элемент из стека без его удаления. Если стек пуст, генерируется исключение типа InvalidOperationException.
- Count: возвращает количество элементов в стеке.
- Contains(): проверяет наличие элемента в стеке и возвращает true в случае нахождения его там.
2. Использование стека. Пример.
var myStack = new Stack<char>(); myStack.Push('A'); myStack.Push('B'); myStack.Push('C'); Console.WriteLine("Исходный стек: "); foreach (char s in myStack) Console.Write(s); Console.WriteLine(); while (myStack.Count > 0) { Console.WriteLine("Pop -> " + myStack.Pop()); } if (myStack.Count == 0) Console.WriteLine("Стек пуст!");
3. Правильная скобочная последовательность.
Правильной скобочной последовательностью называется строка, состоящая только из символов "скобки" (круглых () и квадратных[]), где каждой закрывающей скобке найдётся соответствующая открывающая (причём того же типа).
Программа должна определить, является ли данная скобочная последовательность правильной.
В единственной строке записана скобочная последовательность, содержащая не более 100000 скобок.
Если данная последовательность правильная, то программа должна вывести строку «yes», иначе строку «no».
Console.Write("Введите скобочную последовательность:"); string str = Console.ReadLine(); var myStack = new Stack<char>(); string answer = "yes"; for (int i = 0; i < str.Length; i++) { bool isNotBracket = str[i] != '(' && str[i] != '[' && str[i] != ')' && str[i] != ']'; if (isNotBracket) { continue; } bool isOpeningBracket = str[i] == '(' || str[i] == '['; if (isOpeningBracket) { myStack.Push(str[i]); } if (str[i] == ')') { if (myStack.Count == 0) { answer = "no"; break; } if (myStack.Pop() != '(') { answer = "no"; break; } } if (str[i] == ']') { if (myStack.Count == 0) { answer = "no"; break; } if (myStack.Pop() != '[') { answer = "no"; break; } } } if (myStack.Count != 0) { answer = "no"; } Console.WriteLine(answer);
Задание: Попробуйте самостоятельно изменить программу так, чтобы она работала еще и с фигурными {} скобками.
Итоги занятия.
Стек используется при решении сравнительно небольшого количества задач, но зато, если задача решается с помощью стека, вы получаете простую, короткую и достаточно эффективную программу.
А на следующем занятии нам предстоит вспомнить (если, конечно кто-то успел забыть), что значит «потусоваться» в больших очередях. И с помощью очереди помочь принцу отыскать свою принцессу в самом сложном и запутанном лабиринте.