스 택

2021. 10. 1. 21:20카테고리 없음

첫 번째 주제인 스택을 알아보는 글입니다!

자료구조 시간에 배웠거나, 컴퓨터시스템/컴퓨터구조나 프로그래밍 시간에 들어본 등

대부분의 참가자들에게 익숙한 이름일 것 같습니다.

스택의 간략한 개념과 C(C++), Python에서의 사용법, 스택을 사용한 문제를 알아보겠습니다.

최대한 쉽고 간결하게 쓰도록 노력하겠지만, 

혹시 이해가 잘 안 된다면 조금 더 자세히 다룬 아래 게시물들을 더 읽어보거나 댓글로 질문해주세요!!

https://blog.naver.com/kks227/220781557098

 

스택(Stack) (수정 2019-05-14)

또다른 기본 자료구조 중 하나인 스택(stack)입니다. 스택은 LIFO(Last In First Out) 자료구조인...

blog.naver.com

https://justicehui.github.io/easy-algorithm/2018/06/03/StackSTL/

 

[스택] 스택 STL

서론 이번에는 스택을 구현하기 귀찮을 때 쓰면 좋은 STL을 다룰 것입니다. STL은 stack말고 queue나 deque같은 것도 구현되어 있지만, 그것들은 나중에 해당 자료구조를 할 때 같이 다룰 것입니다. STL

justicehui.github.io

 

목차

 

자료구조가 뭔가요..?

다양한 정의가 있지만, 자료구조는 "데이터를 효율적으로 저장/조회/수정/삭제하는 방법"을 말합니다.

수십 년간 프로그램을 만들며 사람들은 많은 프로그램에서 사용되는 비슷한 구조를 찾아냈고, 

이런 공통적인 구조를 어디서든 구현하고 사용할 수 있도록 정의한 것이 바로 자료구조입니다. 

자료구조를 공부하다 보면 "이런 걸 왜 배우지?" 하는 생각이 들 수도 있는데, 

일단 해당 자료구조의 개념을 익히고 여러 활용을 알게 되면 자연스럽게 이해하게 됩니다.

적절한 자료구조를 잘 활용하면 같은 동작이라도 훨씬 빠르게, 효율적으로  수 있다는 점을 생각하면 더 쉽게 공부할 수 있을 것 같습니다!!

 

스택이란?

스택은 값을 삽입하고, 마지막에 삽입한 값을 읽거나 꺼낼 수 있는 자료구조입니다. 

 

뷔페 가고 싶어요

이렇게 접시가 쌓여 있는 모습을 상상해 봅시다.

접시를 하나씩 쌓는다면 가장 나중에 쌓은 접시는 맨 위에 있는 접시일 것입니다.

접시를 꺼낼 때는 맨 위에 있는 접시만 꺼낼 수 있습니다.

굳이 중간 혹은 아래쪽의 접시를 꺼내고 싶다면 꺼내고 싶은 접시 위에 쌓인 접시를 모두 꺼내고, 

꺼내고 싶은 접시가 맨 위로 오도록 해야 합니다.

이런 식으로 작동하는 자료구조가 스택입니다.

 

뭘 할 수 있나요

- 맨 위 값 가져오기
- 맨 위의 값 삭제하기
- 맨 위에 새로운 값 추가하기
- 스택에 들어 있는 값이 몇 개인지 알아보기

스택에 들어 있는 데이터의 수가 아무리 많아져도 위 연산들은 항상 같은 시간에 돌아갑니다.

(상수 시간이 걸린다는 의미입니다. 잘 모르겠다면 이전 게시물을 참고해 주세요)

 

구현하기에 따라 다른 기능을 더 넣을 수도 있지만, 이 정도의 기능만 있어도 충분합니다.

물론 우리는 이런 기능이 모두 구현된 라이브러리를 사용합니다.

 

어떻게 쓰나요

C(C++)과 Python에서 사용하는 방법을 소개하겠습니다. 

스택을 사용할 때 가장 중요한 것은 빈 스택에서 값을 꺼내거나 읽으면 안 된다는 것입니다.

언어 불문하고 바로 에러가 나기 때문에, 스택에서 값을 꺼내거나 읽을 때는 항상 스택이 비어 있는지 확인해야 합니다.

 

Python의 경우에는 스택 라이브러리는 따로 없지만,

배열에서 append, pop, len 함수로 위 기능을 모두 구현할 수 있어 그냥 배열을 스택처럼 사용하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
stk = [] # 빈 스택 만들기
 
# 스택의 맨 위에 값 추가
stk.append(1# 현재 스택: 1
stk.append(2#현재 스택: 1 2
 
print(stk[-1]) # 스택의 맨 위 값 출력(2)
 
stk.pop() # 맨 위 값 삭제 / 현재 스택: 1
 
print(len(stk)) # 스택의 값의 개수 출력(1)
 
stk.pop()
print(stk[-1]) # 에러(출력할 값이 없음)
cs

 

C++의 경우에는 <stack> 라이브러리에 스택이 구현되어 있습니다.

C++을 모르더라도 확장자만 .cpp으로 하고 C와 동일한 코드를 작성하면 됩니다.

+ using namespace std; 를 main함수 밖에 한 번 적어주어야 편하게 쓸 수 있습니다

+ 스택 배열을 만들어 여러 개의 스택을 쓰고 싶다면 stack<int> stk[1000]; 처럼 선언하고 stk[10].push(1); 처럼 사용하면 됩니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <stack>
using namespace std;
 
int main() {
    stack<int> stk; // int형을 담는 빈 스택 만들기, char / string 등을 쓰면 해당 자료형을 담게 됨
 
    // 스택의 맨 위에 값 추가
    stk.push(1); // 현재 스택: 1
    stk.push(2); // 현재 스택: 1 2
 
    printf("%d\n", stk.top()); // 스택의 맨 위 값 출력(2)
 
    stk.pop(); // 맨 위 값 삭제 / 현재 스택: 1
 
    printf("%d\n", stk.size()); // 스택의 값의 개수 출력(1)
 
    stk.pop(); 
    printf("%d\n", stk.top()); // 에러(출력할 값이 없음)
}
cs

 

Java에서는 java.util.Stack의 Stack 클래스를 이용하면 된다고 합니다

제가 자바를 잘 못해서.. 아래 게시물을 참고하면 좋을 것 같아요

https://coding-factory.tistory.com/601

 

[Java] 자바 Stack 클래스 사용법 & 예제 총정리

Stack이란? 자료 구조 중 하나인 Stack의 사전적 정의는 '쌓다', '더미'입니다. 상자에 물건을 쌓아 올리듯이 데이터를 쌓는 자료 구조라고 할 수 있습니다. Stack의 가장 큰 특징은 나중에 들어간 것

coding-factory.tistory.com

 

알고리즘 문제에서 쓰는 방식

알고리즘 문제풀이에서의 스택 문제는 주로

- 마지막에 넣은 순서대로 꺼내야 할 때

- 짝을 맞춰야 할 때(괄호 문자열 등, 응용되면 어려움)

- 단조 스택_monotone stack 사용(어려움)

 

등의 유형이 있습니다. 이번 대회에서는 쉬운 유형들만 공부해도 충분하지만, 

개인적으로 단조 스택을 사용하는 문제들은 정말 신기하고 재밌다고 생각해서 추천하고 싶습니다!

추가적으로 어떤 수식이 문자열로 주어졌을 때 스택을 이용하면 식을 계산할 수 있는데, 

관심이 있다면 공부해봐도 좋을 것 같습니다

 

연습 문제

대망의 연습 문제입니다. 

어려운 문제일수록 😿를 많이 달았습니다.

"더보기" 에 풀이를 적었습니다. 

스택 실버 문제를 무리없이 풀 수 있다면 본 대회에서도 스택 문제를 풀 수 있을 거라고 예상합니다!!

 

https://www.acmicpc.net/problem/10828 😿

 

10828번: 스택

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 10,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지

www.acmicpc.net

더보기

스택을 쓸 수 있는지 묻는 문제입니다.

빈 스택에서 값을 꺼내거나 읽으려 하지 않는지 항상 확인해야 합니다.

잘 모르겠거나 계속 틀린다면 정답 코드를 참고하세요

C(C++) 정답: http://boj.kr/9cbe617e36f743f0a6b1eae2f37aeb60

Python 정답: http://boj.kr/effb713f88ad4788a9a61493187e92b9


https://www.acmicpc.net/problem/1874 😿😿

 

1874번: 스택 수열

1부터 n까지에 수에 대해 차례로 [push, push, push, push, pop, pop, push, push, pop, push, push, pop, pop, pop, pop, pop] 연산을 수행하면 수열 [4, 3, 6, 8, 7, 5, 2, 1]을 얻을 수 있다.

www.acmicpc.net

더보기

어떤 수를 원하는 순서에 뽑으려면 자신보다 먼저 뽑혀야 하는 수들이 이미 들어갔다가 모두 뽑힌 상태여야 합니다.

따라서 스택에 1부터 N까지의 수를 차례대로 넣으면서 스택의 맨 위 값이 뽑아야 할 값이면 뽑는 것을 반복하고, 이렇게 모든 수를 넣었다 뺄 수 있으면 가능, 못 빼는 수가 생기면 불가능합니다.

C(C++) 정답: http://boj.kr/43a2b1e93e7d440096bbfefd228bc4ba


https://www.acmicpc.net/problem/1406 😿😿

 

1406번: 에디터

첫째 줄에는 초기에 편집기에 입력되어 있는 문자열이 주어진다. 이 문자열은 길이가 N이고, 영어 소문자로만 이루어져 있으며, 길이는 100,000을 넘지 않는다. 둘째 줄에는 입력할 명령어의 개수

www.acmicpc.net

더보기

커서의 앞부분과 뒷부분을 각각 스택으로 생각해 봅시다.

커서와 가까운 문자일수록 각 스택의 윗쪽에 오게 하면

커서가 앞으로 이동하면 앞부분 스택의 맨 위 문자를 뒷부분 스택에 넣고, 앞부분 스택의 맨 위를 삭제하면 됩니다.

비슷한 원리로 모든 연산을 스택으로 구현할 수 있습니다.

C(C++) 정답: http://boj.kr/462ca37b972047b786515e32376bde18


https://www.acmicpc.net/problem/1935 😿😿😿

 

1935번: 후위 표기식2

첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이

www.acmicpc.net

더보기

주어진 식을 앞에서부터 한 글자씩 보면서 피연산자(ABCD..)라면 해당하는 값을 스택에 넣고, 연산자(+-*/)라면 맨 위의 값 두 개를 꺼내서 연산 결과를 스택에 넣으면 됩니다. 최종적으로 스택에 남아 있는 값이 계산 결과입니다.

C(C++) 정답: http://boj.kr/361e93e3d5f241bd9fa6ba6fd7501107

우리가 보통 쓰는 3+2-5 와 같이 연산자가 피연산자 사이에 있는 중위 표기식을 후위 표기식으로 변환하는 것도 스택으로 할 수 있는데, 궁금한 분들은 더 공부해보시길 바랍니다.


https://www.acmicpc.net/problem/17298 😿😿😿😿

조금 어렵습니당 

 

17298번: 오큰수

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄에 수열 A의 원소 A1, A2, ..., AN (1 ≤ Ai ≤ 1,000,000)이 주어진다.

www.acmicpc.net

더보기

 

주어진 순서대로 스택에 수를 넣으면서 스택에 들어 있는 수들을 위에서부터 보았을 때 비내림차순이도록 유지한다고 생각해 봅시다.

비내림차순을 유지하려면 새로 스택에 수를 넣을 때 스택의 맨 위에 넣을 수보다 작은 수가 있으면 안 되므로, 조건에 맞지 않는 수를 모두 뽑고 수를 넣어야 합니다. 

스택에 들어 있던 수 입장에서는 자신 오른쪽에 있는 수 중 자신보다 큰 수가 스택에 들어오는 순간 빠져나가게 됩니다. 따라서 이렇게 각 수의 오큰수를 찾을 수 있습니다.

이중 반복문이 있어 $O(N^2)$ 시간이 걸리는 것 같지만, $N$개의 수가 한 번 들어왔다가 한 번 나가기 때문에 $O(N)$ 시간이 걸립니다.

이렇게 스택에 들어 있는 수들이 오름차순/내림차순 등의 성질을 만족하도록 유지시키는 스킬을 "단조 스택" 또는 "monotone stack" 이라고 합니다.

C++ 정답: http://boj.kr/52d30f920bfb423f88a42f6fdcaebe9e

 


https://www.acmicpc.net/problem/6549 😿😿😿😿😿😿😿😿

이런 건 못 풀어도 되지만,, 오큰수 문제가 너무너무 쉬웠다면 한 번 도전해보세요

만약 온전히 혼자 힘으로 풀었다면 꼭 좋은 선생님 구해서 정보올림피아드를 나가야 합니다

 

6549번: 히스토그램에서 가장 큰 직사각형

입력은 테스트 케이스 여러 개로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, 직사각형의 수 n이 가장 처음으로 주어진다. (1 ≤ n ≤ 100,000) 그 다음 n개의 정수 h1, ..., hn (0 ≤ hi ≤

www.acmicpc.net

더보기

오큰수 문제를 응용하면 각 직사각형마다 왼쪽/오른쪽에서 자신보다 작으면서 가장 가까운 직사각형을 찾을 수 있습니다. 이를 이용하여 각 막대를 완전히 포함하는 직사각형의 너비와 최대 넓이를 찾을 수 있고, 이렇게 찾은 직사각형 넓이의 최댓값이 정답입니다. 정답 코드는 생략하겠습니다.