Stack이란?
스택은 이름만 들어도 무언가가 차곡차곡 쌓이는 이미지가 떠오른다.
맞다.
이미지 그대로 자바에서 스택은 "객체(요소)가 쌓인다" 로 생각하면 된다.
그리고 쌓이는 것이기 때문에 맨 처음, 즉 가장 처음에 넣은 값이 가장 마지막에 빠져나오게 된다.
다른 표현으로는 마지막에 추가된 값이 가장 먼저 나온다고 표현할 수 있다.
우리는 이것을 후입선출(LIFO, Last In First Out)이라고 한다.
사용 방법
Stack 선언
일단 기본적으로 Stack을 사용하기 위해서는 Stack이 있어야 한다.
import java.util.Stack;
public class Main {
public static void main(String[] args) {
// <Integer>는 stack에 Integer 값만 추가하겠다는 의미
Stack<Integer> stack = new Stack<>();
}
}
<Integer> 대신 원하는 객체 타입을 지정할 수 있다. 만약 문자열을 넣고 싶다면 <String>으로 작성하면 된다.
이제 Stack을 선언했으니, 값을 넣을 수 있다.
Stack에 값 넣기 - push(값)
Stack에 값을 넣는 방법은 push다. 우리는 Stack을 stack이라는 이름으로 선언했다.
즉, stack.push(값) 을 통해서 요소를 쌓을 수 있다.
다음 코드를 보자.
Stack<Character> stack = new Stack<>();
stack.push('A'); // stack에 문자 A 추가
<Character> 값만 넣을 수 있는 stack에 문자 'A'를 추가해 보았다.
이제 stack에는 하나의 값이 들어있고, 하나뿐이기 때문에 바로 뽑을 수 있는 값은 'A'가 된다.
그럼 이제 값이 있으니 값을 내보낼 수도 있다.
Stack에서 값 제거 - pop()
지금 stack에는 'A'라는 값이 들어있다. 값을 넣었으니, 값을 제거할 수도 있다.
제거하는 메서드는 stack.pop() 으로 괄호 안에 아무것도 작성하면 안 된다.
다음 코드를 보자.
Stack<Character> stack = new Stack<>();
stack.push('A');
stack.pop(); // 'A' 삭제
이제 stack에 있던 'A'는 삭제되었다.
어? 그런데 나는 삭제가 아니라 뽑아서 사용하고 싶은데??? 라고 생각했다면?
다음과 같은 방식으로 사용이 가능하다.
Stack<Character> stack = new Stack<>();
stack.push('A');
char value = stack.pop(); // char 타입의 value에 stack에서 pop한 값 저장
System.out.println(value); // value에는 'A'가 저장되므로 'A' 출력
와 너무 간단하다!!!!!!!!!!
이렇게 하면 값을 stack에 넣은 후 원할 때 뽑아서 출력까지 할 수 있다.
물론 stack.push(value)를 하면 value에 저장된 'A'가 다시 stack에 들어간다.
Stack 추가 활용 1 - peek(), size()
이제 여러분은 stack에 값을 추가하고 삭제할 수 있게 되었다.
그런데 무언가 부족하다... stack이 차례로 쌓이고, 맨 위에 것부터 꺼낼 수 있다면...
가장 위의 값을 삭제하지 않고, 확인만 할 수는 없나?
가능하다!!!
그것이 바로 stack.peek() 로, 가장 위에 저장된 값을 가져올 수 있다. 마찬가지로 괄호에 아무것도 작성하면 안 된다.
다음 코드를 보자.
Stack<Character> stack = new Stack<>();
stack.push('A');
char value = stack.peek();
System.out.println(value);
stack.pop() 에서 사용했던 것과 비슷하다.
하지만 차이점이 있다면, 바로 stack에는 여전히 'A'라는 값이 남아있다는 것!
그래도 부족하다... stack에 값을 넣고, 빼고, 조회도 했다... 그런데 아직도 부족하다...
stack에 값이 몇 개 있는지도 알고 싶다...
이것도 가능하다!!
바로 stack.size() 를 통해서 stack에 요소가 몇 개나 있는지 알 수 있다.
개수이기 때문에 정수 자료형이 필요하다.
다음 코드를 보자
Stack<Character> stack = new Stack<>();
stack.push('A');
int size1 = stack.size(); // 이 시점에는 'A'만 있으므로 사이즈는 1
stack.push('B');
int size2 = stack.size(); // 이 시점에는 'B'도 있으므로 사이즈는 2
stack.pop();
int size3 = stack.size(); // 맨 위 값인 'B'가 없어져서 사이즈는 1
이렇게 값이 변경될 때마다 size()는 달라질 수 있다.
하지만 한 번 int size1에 1이 저장된 이후 push()를 여러 번 해도 size1에는 계속 1이 저장되어 있다.
왜냐? 이미 변수에 저장했으니깐~~~~
size1을 다시 다른 값으로 바꾸지 않는 이상 그대로 1이 될 것이다.
지금까지 push(), pop(), peek(), size()를 배웠다.
그럼 이제 이것들이 어떻게 움직이는지 확인해 보자

순서는
push('A') > push('B') > push('C') > pop() > push('D') > push('E') > pop() > pop() > pop() > pop()
으로 진행된다.
Stack 추가 활용 2 - isEmpty()
이름으로 눈치 챘을까??
stack.isEmpty()..... 바로 stack이 비어있는가? 를 확인할 수 있는 메서드다.
물론 stack.size()를 통해서 확인할 수도 있다.
하지만 이것의 장점은 바로 stack이 비어있는지를 boolean값으로 바로 받을 수 있다는 것!!!!!
다음 코드를 보자
Stack<Character> stack = new Stack<>();
stack.push('A');
System.out.println(stack.isEmpty()); // 'A'가 있으므로 false
stack.pop();
boolean result = stack.isEmpty() // 이렇게 저장도 할 수 있다.
System.out.println(result); // 'A'를 제거했으므로 true
이렇게 활용할 수 있다.
처음에는 'A'라는 값이 있으니 isEmpty() 라는 물음에 false로 대답한다.
그런데 다음에는 pop()을 해서 stack이 비어있으므로, isEmpty() 라는 물음에 true로 대답하게 된다.
너무 쉽다. 그러니 바로 스크롤 내리지 말고 꼭 잘 읽어보자.
사실 Stack이라는 것은 오래전에 구현되었기 때문에 요즘은 Deque라는 것을 많이 쓴다.
설명하자면 길지만, 간단히 말해서 구식이고, 무겁기 때문이다.
아니 그냥 한 줄만 작성하면 되는데 뭐가 무거운 거야?? 에 대해서는 각자 조사해서 댓글에 정리 부탁
공식 문서에서도 Deque를 권장하고 있지만, 지금 단계에서는 Stack을 사용해 보도록 하고, Deque에 관해서는 더 나중에 알아보도록 하자.