후입선출(LIFO:Last In First Out) 자료구조
데이터가 입력된 순서의 역순으로 처리되어야 할때 사용
-> ex) 함수 콜 스택, 수식 계산, 인터럽트(예상 치 못한 일) 처리 등
기본적으로 데이터 추가, 데이터 꺼내기, 스택 공간 확인 동작으로 이루어짐
데이터 추가(Push) : 스택의 가장 마지막 위치에 데이터 추가
데이터 꺼내기(Pop) : 스택의 가장 마지막 위치에서 데이터 꺼냄
package org.example;
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Stack stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
stack.push(5);
System.out.println(stack);
stack.pop(); // 5가 pop 됨
System.out.println(stack);
System.out.println(stack.peek()); // peek은 가장 위에 있는 값 보여줌 -> 스택에 변화 X
System.out.println(stack);
System.out.println(stack.contains(1)); // true
System.out.println(stack.size()); // 4
System.out.println(stack.empty()); // false;
stack.clear();
System.out.println(stack); // 모두 지워짐, 이상태에서 팝 하면 에러 발생
}
}
class MyStack1{
ArrayList list;
MyStack1(){
this.list = new ArrayList();
}
public boolean isEmpty(){
return this.list.size() == 0;
}
public void push(int data){
this.list.add(data);
}
public Integer pop(){
if(this.isEmpty()){
System.out.println("Stack is empty!");
return null;
}
// ArrayList가 Generic하게 되어있지 않아서 int로 형변환을 하지 않으면 Object 타입임!
int data = (int)this.list.get(this.list.size()-1);
this.list.remove(this.list.size() - 1);
return data;
}
public Integer peek(){
if(this.isEmpty()){
System.out.println("Stack is empty!");
return null;
}
return (int)this.list.get(this.list.size()-1);
}
public void printStack(){
System.out.println(this.list);
}
}
class MyStack2{
int[] arr;
int top = -1;
MyStack2(int size){
arr = new int[size];
}
public boolean isEmpty(){
return this.top == -1? true: false;
}
public boolean isFull(){
return this.top == this.arr.length - 1? true: false;
}
public void push(int data){
if(this.isFull()){
System.out.println("스택이 가득찼습니다!");
return;
}
this.top += 1; this.arr[this.top] = data;
}
public Integer pop(){
if(this.isEmpty()){
System.out.println("Stack is Empty");
return null;
}
int data = this.arr[top];
this.top -= 1; // 이때 데이터 남아 있다는 점은 유의
return data;
}
public Integer peek(){
if(this.isEmpty()){
System.out.println("Stack is Empty");
return null;
}
return this.arr[top];
}
public void printStack(){
for(int i : arr){
System.out.print(i + " ");
}
System.out.println();
}
}
import java.util.Stack;
// 문자열 뒤집기
// 입출력 예시 -> 입력 :"Hello" 출력 : "olleH"
// 1 3 5 7 9 -> 9 7 5 3 1
public class Practice5 {
public static String reverseString(String str){
Stack stack = new Stack();
String result = "";
for(String s : str.split("")){
stack.push(s);
}
while(!stack.isEmpty()){
result += stack.pop();
}
return result;
}
public static void main(String[] args) {
String result = reverseString("Hello");
System.out.println("result = " + result);
result = reverseString("1 3 5 7 9");
System.out.println("result = " + result);
}
}
public class Practice6 {
// 괄호짝 검사
private static void checkParenthesis(String str) {
Stack stack = new Stack();
boolean checkFlag = true;
for(String s : str.split("")){
if(s.equals("(")){
stack.push(s);
}else{
if(stack.isEmpty()){
checkFlag = false;
break;
}else{
stack.pop();
}
}
}
if(checkFlag && stack.isEmpty()){
System.out.println("PASS!");
}else{
System.out.println("FAIL!");
}
}
public static void main(String[] args){
// Test code
checkParenthesis("("); //FAIL
checkParenthesis(")"); //FAIL
checkParenthesis("()"); //PASS
checkParenthesis("()()()"); //PASS
checkParenthesis("(())()"); //PASS
checkParenthesis("(((()))"); //FAIL
}
}
public class Practice7 {
public static double calculate(String str) {
Stack<Double> stack = new Stack();
for(String s : str.split(" ")) {
if(s.equals("+")){
stack.push(stack.pop() + stack.pop());
}else if(s.equals("-")){
stack.push(-stack.pop() + stack.pop());
}else if(s.equals("*")){
stack.push(stack.pop() * stack.pop());
}else if(s.equals("/")){
stack.push(1/stack.pop() * stack.pop());
}else{
stack.push(Double.parseDouble(s));
}
}
return stack.pop();
}
public static void main(String[] args) {
//Test code
System.out.println(calculate("2 2 +")); // 4
System.out.println(calculate("2 2 -")); // 0
System.out.println(calculate("2 2 *")); // 4
System.out.println(calculate("2 2 /")); // 1
System.out.println(calculate("1 1 + 2 * 3 * 2 / 5 -")); // 1
System.out.println(calculate("5 2 * 3 - 8 * 4 /")); // 14
}
}
마이너스 부분과 나누기 부분 유의해서 보자!
// 두 문자열 비교 -> 단 #는 바로 이전에 문자를 삭제하는 기능이라 가정
// 입출력 예시 -> 입력 s1:"tree", s2:"th#ree" -> true
// 입력 s1 = "ab#a", s2 = "aab#" -> true
// 입력 s1 = "wo#w", s2 = "ww#o" -> false
public class Practice8 {
public static boolean stringCompare(String s1, String s2){
String s1After = doBackSpace(s1);
String s2After = doBackSpace(s2);
return s1After.equals(s2After);
}
public static String doBackSpace(String s){
Stack stack = new Stack();
for(char c : s.toCharArray()){
if(c == '#' && !stack.isEmpty()){
stack.pop();
}else{
stack.push(c);
}
}
return String.valueOf(stack);
}
public static void main(String[] args) {
//Test code
System.out.println(stringCompare("tree", "th#ree"));
System.out.println(stringCompare("ab#a", "aab#"));
System.out.println(stringCompare("wo#w", "ww#o"));
}
}
스택은 맨 위에다가 뭘 쌓고 빼거나, 맨 위에 뭐가 있는지에만 관심을 가질 때 주로 사용
스택이라면, 자료구조 시간에 반드시 등장하는! 올바른 괄호 문자열 판단
괄호 문자열은 다음과 같은 규칙으로 재귀적으로 생성됨
올바른 괄호 문자열 판단 방법
2번 예시 : ( ], (()], ), ())
3번 예시 : (( )
위와 같은 조건이 통하는 이유는 괄호식이 바깥쪽으로 이어 붙어져 확장되어 나가는 구조이기 떄문
-> 즉 지금 닫는 괄호를 보았다면, 그것은 반드시 최근에 연 괄호를 닫기 위한 것
-> 최근에 연 괄호와 종류가 맞다면 정상적인 것이고, 아니라면 잘못된 문법