Структурите от данни играят ключова роля в света на програмирането. Те ни помагат да организираме нашите данни по начин, който може да се използва ефективно. Стекът е една от най-простите структури от данни.
Нека научим за стека и неговата реализация в Python.
Съдържание
Какво е стек?
Купчината е подобна на купчина книги, столове и т.н. в реалния живот. И следва принципа Последен влязъл/Пръв излязъл (LIFO). Това е най-простата структура от данни. Нека видим сценария с пример от реалния свят.
Да кажем, че имаме купчина книги, както следва.
Когато искаме третата книга отгоре тогава, трябва да премахнем първите две книги отгоре, за да извадим третата книга. Тук най-горната книга отива последна в купчината и е първа от купчината. Стекът на структурата на данните следва същия принцип Last-in/First-out (LIFO) в програмирането.
Операции в стека
Има основно две операции в стека
1. натискане (данни)
Добавя или избутва данните в стека.
2. поп()
Премахва или изважда най-горния елемент от стека.
Вижте илюстрациите по-долу на операции за натискане и изскачане.
Ще напишем някои помощни функции, които ни помагат да получим повече информация за стека.
Да ги видим.
надниквам()
Връща най-горния елемент от стека.
празно е()
Връща дали стекът е празен или не.
Достатъчно концептуални аспекти на структурата на данните на стека. Нека преминем към изпълнението без повече шум.
Предполагам, че имате инсталиран Python на вашия компютър, ако не, можете също да опитате онлайн компилатора.
Реализация на стека
Внедряването на стека е най-лесното в сравнение с други реализации на структура от данни. Можем да внедрим стека по много начини в Python.
Нека да ги видим всички един по един.
#1. списък
Ще имплементираме стека, като използваме списъка в клас. Нека видим стъпка по стъпка изпълнението на стека.
Стъпка 1: Напишете клас, наречен Stack.
class Stack: pass
Стъпка 2: Трябва да поддържаме данните в списък. Нека добавим празен списък в класа Stack с елементи на име.
class Stack: def __init__(self): self.elements = []
Стъпка 3: За да поставим елементите в стека, ни трябва метод. Нека напишем push метод, който приема данни като аргумент и ги добавя към списъка с елементи.
class Stack: def __init__(self): self.elements = [] def push(self, data): self.elements.append(data) return data
Стъпка 4: По същия начин, нека напишем метода pop, който изважда най-горния елемент от стека. Можем да използваме метода pop на типа данни списък.
class Stack: ## ... def pop(self): return self.elements.pop()
Завършихме внедряването на стека с необходимите операции. Сега нека добавим помощните функции, за да получим повече информация за стека.
Стъпка 5: Можем да получим най-горния елемент от стека, като използваме отрицателния индекс. Кодовият елемент [-1] връща последния от списъка. Това е най-горният елемент на стека в нашия случай.
class Stack: ## ... def peek(self): return self.elements[-1]
Стъпка 6: Ако дължината на списъка с елементи е 0, тогава стекът е празен. Нека напишем метод, който връща дали елементът е празен или не.
class Stack: ## ... def is_empty(self): return len(self.elements) == 0
Завършихме внедряването на стека с помощта на типа данни списък.
о! изчакайте, току-що го внедрихме. Но не видях как да го използвам. Как да го използваме тогава?
Елате да видим как да го приложим. Трябва да създадем обект, за да може класът Stack да го използва. Не е голяма работа. Нека първо го направим.
class Stack: ## ... if __name__ == '__main__': stack = Stack()
Създадохме стековия обект и сме готови да го използваме. Нека следваме стъпките по-долу, за да тестваме операциите на стека.
- Проверете дали стекът е празен или не, като използвате метода is_empty. Трябва да върне True.
- Избутайте числата 1, 2, 3, 4, 5 в стека, като използвате метода на натискане.
- Методът is_empty трябва да върне False. Провери го.
- Отпечатайте най-горния елемент, като използвате метода на надникване.
- Извадете елемента от стека, като използвате метода за изваждане.
- Проверете елемента peek. Трябва да върне елемента 4.
- Сега извадете всички елементи от стека.
- Методът is_empty трябва да върне True. Провери го.
Нашата реализация на стека е завършена, ако премине всички горни стъпки. Опитайте се да напишете кода за горните стъпки.
Вие ли написахте кода? Не, не се притеснявайте, проверете кода по-долу.
class Stack: def __init__(self): self.elements = [] def push(self, data): self.elements.append(data) return data def pop(self): return self.elements.pop() def peek(self): return self.elements[-1] def is_empty(self): return len(self.elements) == 0 if __name__ == '__main__': stack = Stack() ## checking is_empty method -> true print(stack.is_empty()) ## pushing the elements stack.push(1) stack.push(2) stack.push(3) stack.push(4) stack.push(5) ## again checking is_empty method -> false print(stack.is_empty()) ## printing the topmost element of the stack -> 5 print(stack.peek()) ## popping the topmost element -> 5 stack.pop() ## checking the topmost element using peek method -> 4 print(stack.peek()) ## popping all the elements stack.pop() stack.pop() stack.pop() stack.pop() ## checking the is_empty method for the last time -> true print(stack.is_empty())
ура! ние завършихме внедряването на стека от нулата, използвайки типа данни списък. Ще видите резултата, както е споменато по-долу, ако изпълните горния код.
True False 5 4 True
Можем директно да използваме типа данни списък като стек. Горната реализация на стека ви помага да разберете реализацията на стека и в други езици за програмиране.
Можете също да разгледате тези статии, свързани със списъка.
Нека видим вградения deque от вградения модул за колекции, който може да действа като стек.
#2. deque от колекции
Реализира се като двустранна опашка. Тъй като поддържа добавянето и премахването на елементи от двата края. Следователно можем да го използваме като стек. Можем да го накараме да следва LIFO принципа на стека.
Реализира се с помощта на други структури от данни, наречени двойно свързан списък. Така че изпълнението на вмъкването и изтриването на елементи е последователно. Достъпът до елементи от средния свързан списък отне O(n) време. Можем да го използваме като стек, тъй като няма нужда от достъп до средните елементи от стека.
Преди да внедрим стека, нека видим методите, които се използват за внедряване на стека с помощта на опашката.
- append(data) – използва се за изпращане на данните към стека
- pop() – използва се за премахване на най-горния елемент от стека
Няма алтернативни методи за peek и is_empty. Можем да отпечатаме целия стек вместо метода peek. След това можем да използваме метода len, за да проверим дали стекът е празен или не.
Нека внедрим стека с помощта на deque от модула за колекции.
from collections import deque ## creating deque object stack = deque() ## checking whether stack is empty or not -> true print(len(stack) == 0) ## pushing the elements stack.append(1) stack.append(2) stack.append(3) stack.append(4) stack.append(5) ## again checking whether stack is empty or not -> false print(len(stack) == 0) ## printing the stack print(stack) ## popping the topmost element -> 5 stack.pop() ## printing the stack print(stack) ## popping all the elements stack.pop() stack.pop() stack.pop() stack.pop() ## checking the whether stack is empty or not for the last time -> true print(len(stack) == 0)
Това е. Научихме как да внедряваме стек, използвайки deque от вградения модул за колекции. Ще получите резултата, както е споменато по-долу, ако изпълните горната програма.
True False deque([1, 2, 3, 4, 5]) deque([1, 2, 3, 4]) True
Досега сме виждали два начина за внедряване на стека. Има ли други начини за внедряване на стек? да! Нека видим окончателния начин за внедряване на стек в този урок.
#3. LifoQueue
Самото име LifoQueue казва, че следва принципа LIFO. Следователно можем да го използваме като стек без никакво съмнение. Той е от вградената модулна опашка. LifoQueue предоставя някои удобни методи, които са полезни при внедряването на стека. Да ги видим
- put(data) – добавя или избутва данните към опашката
- get() – премахва или изважда най-горния елемент от опашката
- празен() – връща дали стекът е празен или не
- qsize() – връща дължината на опашката
Нека внедрим стека с помощта на LifoQueue от модула за опашка.
from queue import LifoQueue ## creating LifoQueue object stack = LifoQueue() ## checking whether stack is empty or not -> true print(stack.empty()) ## pushing the elements stack.put(1) stack.put(2) stack.put(3) stack.put(4) stack.put(5) ## again checking whether stack is empty or not -> false print(stack.empty()) ## popping all the elements print(stack.get()) print(stack.get()) print(stack.get()) ## checking the stack size print("Size", stack.qsize()) print(stack.get()) print(stack.get()) ## checking the whether stack is empty or not for the last time -> true print(stack.empty())
Ще получите изхода, споменат по-долу, ако изпълните горната програма, без да я променяте.
True False 5 4 3 Size 2 2 1 True
Приложение на Stack
Сега имате достатъчно познания за стековете, за да ги приложите в проблеми с програмирането. Нека да видим проблем и да го разрешим с помощта на стек.
Даден е израз, напишете програма, за да проверите дали скобите, скобите и фигурните скоби са балансирани правилно или не.
Нека да видим някои примери.
Вход: „[{}]([])”
Изход: балансиран
Вход: „{[}]([])”
Изход: Небалансиран
Можем да използваме стека, за да разрешим горния проблем. Нека да видим стъпките за решаване на проблема.
- Създайте стек за съхраняване на знаците.
- Ако дължината на израза е нечетна, тогава изразът не е балансиран
- Итерация през дадения израз.
- Ако текущият знак е отварящата скоба от ( или { или [, then push it to stack.
- Else if the current character is a closing bracket ) or } or ]след което изскочи от стека.
- Ако изскоченият знак съвпада с началната скоба, тогава продължете, иначе скобите не са балансирани.
- След итерацията, ако стекът е празен, тогава уравнението е балансирано, в противен случай уравнението е небалансирано.
Можем да използваме зададения тип данни за проверка на съответствието на скоби.
## stack class Stack: def __init__(self): self.elements = [] def push(self, data): self.elements.append(data) return data def pop(self): return self.elements.pop() def peek(self): return self.elements[-1] def is_empty(self): return len(self.elements) == 0 def balance_check(expression): ## checking the length of the expression if len(expression) % 2 != 0: ## not balanced if the length is odd return False ## for checking opening_brackets = set('([{') pairs = set([ ('(',')'), ('[',']'), ('{','}') ]) ## stack initialization stack = Stack() ## iterating through the given expression for bracket in expression: ## checking whether the current bracket is opened or not if bracket in opening_brackets: ## adding to the stack stack.push(bracket) else: ## popping out the last bracket from the stack popped_bracket = stack.pop() ## checking whether popped and current bracket pair if (popped_bracket, bracket) not in pairs: return False return stack.is_empty() if __name__ == '__main__': if balance_check('[{}]([])'): print("Balanced") else: print("Not Balanced") if balance_check('{[}]([])'): print("Balanced") else: print("Not Balanced")
Можем да използваме стека за решаване на много повече проблеми. Горният проблем е един от тях. Опитайте се да приложите концепцията за стека навсякъде, където смятате, че е най-подходящо за вас.
Заключение
ах! Завършихте урока. Надявам се урокът да ви е харесал толкова, колкото и аз, докато го правех. Това е всичко за урока.
Приятно кодиране 🙂 👨💻