Stacks - Забони барномасозии C++ барои барномасозии рақобатӣ
дарс кушода мешавад…
Week 10Stacks, Queues, Deques and Simulation Problems
Stacks
A pile you can only touch at the top: push, top and pop, a vector or a string used as a stack, matching brackets, a postfix calculator, and a stack that knows its minimum.
Назария
Дарси 1 аз 7
Хониш: 21 дақиқа
Саволҳо: 5
In Week 9 you met the call stack: every new call goes on top, only the top
call runs, and the last call made is the first to return. That way of keeping
things — a pile you can only touch at the top — is useful far beyond function
calls, and C++ has it ready-made.
Think of a pile of plates. A clean plate goes on top, and you take the next one
from the top. The plate at the bottom waits until every plate above it has gone.
Last in, first out — programmers write it LIFO — and a pile that works
this way is called a stack.
stack: push, top, pop
Operation
What it does
st.push(x)
puts x on top
st.top()
the top element — it stays on the stack
st.pop()
removes the top element and gives back nothing
st.empty()
true if there is nothing on the stack
st.size()
how many elements are on it
Each of these takes a single step, however big the stack is. Two rules save a
lot of grief:
pop()returns nothing. To use the top element, read it with top()
first, then pop().
Never call top() or pop() on an empty stack. C++ doesn't stop you: the
program crashes or quietly reads garbage. Check !st.empty() first, unless
you are sure.
навбатӣ
Practice: Stacks
Four problems for the stack: brackets, letters that cancel, a postfix calculator and a stack with its minimum.
A stack of plates: the last one in is the first one out
C++
1#include <bits/stdc++.h>
2using namespace std;
3
4int main() {
5 ios_base::sync_with_stdio(false);
6 cin.tie(NULL);
7
8 stack<int> st;
9 st.push(7);
10 st.push(2);
11 st.push(9);
12 while (!st.empty()) {
13 cout << st.top() << " ";
14 st.pop();
15 }
16 cout << "\n";
17 return 0;
18}
An empty stack
сатр 8
st holds nothing yet. The panel shows the bottom of the stack on the left and the top on the right.
st (bottom → top)0 катак
пахш кун
1 / 15
Whatever goes in comes out in reverse order, so reversing a list is a stack's
simplest job:
For 5 and 4 8 15 16 23 it prints 23 16 15 8 4.
Printing a stack in order
Some problems need the whole stack at the end, in order. Here is one:
You are given the keys someone pressed, as one line. A letter types itself;
# is backspace: it deletes the last letter typed, or does nothing if the text
is empty. Print the text that is left. For cay#t the answer is cat.
Input
Output
The text behaves like a stack: typing puts a letter on top, and backspace takes
the top letter off. But a stack only lets you see its top, so at the end the
letters come off it backwards, the last one typed first.
A stack reverses whatever passes through it, so a second stack reverses
them back. Pour the first stack into the second one — top(), push() onto the
other stack, pop() — and the first letter typed ends up on top. Popping the
second stack now gives the text in order:
For cay#t, the letters c, a and y are typed, # deletes the y, and t
follows: the stack holds c a t with t on top. Poured over, it holds t a c
with c on top, and it prints cat. The empty() check matters when backspace
comes first: for ##hi, the two # find nothing to delete and the program
prints hi. Without the check, pop() on an empty stack would break the
program.
Pairs that cancel
In some problems two equal neighbours vanish together,
and the letters on either side of them become neighbours, which may vanish in
turn. A stack handles the whole chain reaction: compare each new letter with
the top, and pop instead of pushing when they are equal.
For xyyxz, the two ys vanish, which brings the two xs together, and they
vanish too: z is left. Whenever a pair vanishes, the new top is exactly the
letter that has just become the next neighbour. To print the letters left, in
order, pour the stack into a second one, as in the backspace program.
Matching brackets
You are given a string made of the brackets (, ), [, ], { and }.
It is balanced when every opening bracket is closed by one of the same
kind and the pairs nest properly: ([]{()}) is balanced, and ([)] is not.
Print YES if the string is balanced and NO if it isn't.
Input
Output
The bracket that has to close first is always the one opened most recently
— and "most recently" is exactly what the top of a stack is.
For ([]{()}) it prints YES. There are exactly three ways to fail, one for
each check:
String
Where it breaks
([)]
) arrives while [ is on top: the wrong kind
())
the second ) arrives with the stack empty: nothing to close
(()
the string ends with ( still on the stack: never closed
Now you are the stack. Push, pop, and stop each broken string at the exact
bracket where it breaks:
Be the stackсанҷида бин!
One kind of bracket: a counter is enough
If the only brackets are ( and ), every element on the stack is the same
(. Then only the stack's size matters, and an int can keep that:
At the end, broken counts the ) that found no partner, and open counts the
( that were never closed. The string is balanced when both are zero; for
))(((), both are 2.
A postfix calculator
We write 3 + 4, with the operator between its numbers. In postfix
notation the operator comes after them: 3 4 +. It looks odd, but it needs
no brackets and no rules about which operation goes first — the order of the
tokens says everything. (6 - 2) * 3 is 6 2 - 3 *, and 5 + (1 + 2) * 4 is
5 1 2 + 4 * +.
A stack works it out in one pass:
a number is pushed;
an operator pops the two most recent numbers and pushes the result. The
top is the later number y, the one below it is the earlier x, and the
result is x op y. For - the order matters: 6 2 - is 4, not −4.
At the end, the one number on the stack is the answer.
A postfix calculator: numbers wait on the stack, operators eat two
C++
1#include <bits/stdc++.h>
2using namespace std;
3
4int main() {
5 ios_base::sync_with_stdio(false);
6 cin.tie(NULL);
7
8 vector<string> toks = {"6", "2", "-", "3", "*"};
9 stack<long long> st;
10 for (string tok : toks) {
11 if (tok == "+" || tok == "-" || tok == "*") {
12 long long y = st.top();
13 st.pop();
14 long long x = st.top();
15 st.pop();
16 if (tok == "+") {
17 st.push(x + y);
18 } else if (tok == "-") {
19 st.push(x - y);
20 } else {
21 st.push(x * y);
22 }
23 } else {
24 st.push(stoll(tok));
25 }
26 }
27 cout << st.top() << "\n";
28 return 0;
29}
The tokens
сатр 8
6 2 - 3 * is postfix for (6 - 2) * 3: each operator comes after its two numbers.
toks5 катак
"6"
"2"
"-"
"3"
"*"
0
1
2
3
4
st (bottom → top)0 катак
tok—y—x—
пахш кун
1 / 31
Now the same as a problem:
The first line holds m, the second m tokens of a postfix expression, with
spaces between them. A token is a whole number, possibly negative, or one of
the operators +, - and *. Print the value of the expression.
Input
Output
Read each token as a string. A token is an operator only if it is exactly
"+", "-" or "*"; anything else is a number — including -3, which starts
with a minus sign but is a number, not an operator. stoll(tok) turns the text
into a long long:
For the 9 tokens 5 1 2 + 4 * + -3 - it prints 20: 5 + (1 + 2) · 4 is 17, and
17 − (−3) is 20. Keep long long on the stack — a few multiplications are
enough to outgrow an int.
A stack that knows its minimum
Some problems ask a stack for its smallest element, again and again:
There are q commands. push x puts x on the stack; pop removes the top
element, or does nothing if the stack is empty; min prints the smallest
element on the stack, or empty if there is none.
Input
Output
There can be thousands of min commands, while pushes and pops keep changing
the stack. Looking through the whole stack for every one is far too slow.
The trick: store with every element the smallest value from it down to the
bottom. When you push x, that is min(x, the minimum stored at the old top). When you pop, nothing needs fixing: the elements below never changed, so
the minimum stored at the new top is still right. The answer is always
st.top().second.
After push 6, push 9 and push 2, the stored minimums are 6, 6 and 2, so
min prints 2. After one pop it prints 6; when everything is gone,
empty; and after push 7, 7.
Check your understanding
Checking brackets with a stack
An opening bracket: push it. It waits for its partner.
A closing bracket: the top of the stack must be its partner. If the stack is empty, or the top is a different kind, the string breaks right here.
Otherwise pop: the pair is complete, and the bracket below becomes the one waiting.
At the end, the stack must be empty. Anything left is a bracket that was never closed.
Did you know?
Postfix is also called Reverse Polish notation, after the Polish logician
Jan Łukasiewicz, who in the 1920s wrote operators before their numbers to do
without brackets. From 1968, Hewlett-Packard built calculators that worked in
postfix: to add 3 and 4, you pressed 3, ENTER, 4, + — and inside, a
stack did exactly what this lesson's program does.
stack<int> st; // an empty stack of ints
худро санҷ1 хол
An empty stack<int> st gets push(5), push(8), pop(), push(3), push(1), pop(). What is st.top() now?
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
int x = st.pop(); takes the top element off the stack and stores it in x.
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
What is the value of the postfix expression 4 2 5 * + 1 -?
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
A stack keeps pairs (value, smallest value from here down). It gets pushes of 5, 3, 8 and 1, then two pops. What is st.top().second now?
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
худро санҷ1 хол
Which of these bracket strings is balanced?
Як ҷавобро интихоб кунед
Барои ҷавоб додан ва нигоҳ доштани пешрафт ворид шавед.Ворид шудан
cay#t
cat
([]{()})
YES
9
5 1 2 + 4 * + -3 -
20
11
push 6
push 9
push 2
min
pop
min
pop
pop
min
push 7
min
2
6
empty
7
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int n; cin >> n; stack<int> st; for(int i = 0; i < n; i++){ int x; cin >> x; st.push(x); // the newest number goes on top} while(!st.empty()){ cout << st.top()<< " "; // look at the top... st.pop(); // ...then take it off} cout << "\n"; return 0;}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); string keys; cin >> keys; stack<char> text; // the letters typed so far, the last one on top for(char c : keys){ if(c == '#'){ if(!text.empty()){ text.pop(); // backspace: take the top letter off}} else{ text.push(c); // a letter goes on top}} stack<char> poured; // pouring reverses the order once more while(!text.empty()){ poured.push(text.top()); text.pop();} while(!poured.empty()){ cout << poured.top(); // the first letter typed is on top now poured.pop();} cout << "\n"; return 0;}
stack<char> st; // the letters still standingfor(char c : s){ if(!st.empty() && st.top() == c){ st.pop(); // c and the top vanish together} else{ st.push(c);}}
#include <bits/stdc++.h>using namespace std;bool matches(char open, char close){ return(open == '(' && close == ')') ||(open == '[' && close == ']') ||(open == '{' && close == '}');}int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); string s; cin >> s; stack<char> st; bool ok = true; for(char c : s){ if(c == '(' || c == '[' || c == '{'){ st.push(c); // an opening bracket waits on the stack} else if(st.empty() || !matches(st.top(), c)){ ok = false; // nothing to close, or the wrong type break;} else{ st.pop(); // the pair is complete}} if(!st.empty()){ ok = false; // some brackets were never closed} cout <<(ok ? "YES" : "NO")<< "\n"; return 0;}
int open = 0, broken = 0;for(char c : s){ if(c == '('){ open++; // one more ( is waiting} else if(open > 0){ open--; // this ) closes a waiting (} else{ broken++; // this ) has nothing to close}}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int m; cin >> m; stack<long long> st; for(int i = 0; i < m; i++){ string tok; cin >> tok; if(tok == "+" || tok == "-" || tok == "*"){ long long y = st.top(); // the later value st.pop(); long long x = st.top(); // the earlier value st.pop(); if(tok == "+"){ st.push(x + y);} else if(tok == "-"){ st.push(x - y);} else{ st.push(x * y);}} else{ st.push(stoll(tok)); // a number: text -> long long}} cout << st.top()<< "\n"; return 0;}
#include <bits/stdc++.h>using namespace std;int main(){ ios_base::sync_with_stdio(false); cin.tie(NULL); int q; cin >> q; stack<pair<int, int>> st; // (value, smallest value from here down) for(int i = 0; i < q; i++){ string cmd; cin >> cmd; if(cmd == "push"){ int x; cin >> x; int low = x; if(!st.empty()){ low = min(x, st.top().second);} st.push({x, low});} else if(cmd == "pop"){ if(!st.empty()){ st.pop(); // the ones below still know their minimum}} else{ if(st.empty()){ cout << "empty\n";} else{ cout << st.top().second<< "\n";}}} return 0;}