스텍


강의노트 2강에서는 자료구조 중 Stack과 Queue에 대하여 공부해보고자 합니다.

먼저 Stack에 대하여 알아보겠습니다.

1) 스텍(Stack)

스텍은 자료를 저장하는 방식으로 LIFO 구조를 따릅니다.

LIFO는 Last-In Frist-Out의 약자로 후입선출의 구조입니다.

일상생활에서의 끼우는 형식의 동전지갑이나 트럼프 카드 더미를 생각하시면 이해하시기 편합니다.

stack example
일상생활에서 볼 수 있는 Stack 구조

출처 : (좌)http://bitly.kr/0jf5lF / (우)http://bitly.kr/TpwPkB

 

2) Stack Operation

- push(object) : 스텍에 element를 삽입합니다.

- object pop() : 스텍에 있는 element를 제거합니다. // 제일 마지막에 push된 element가 제거됩니다.

- object top() : 스텍 최상단의 element를 보여줍니다.

- integer size() : 스택의 크기를 보여줍니다.

- boolean isEmpty() : 스텍이 비어져있는지 아닌지 판단합니다.


!) Stack Opearation Example

더보기
Operation Output In_Stack
push(3) - (3)
push(5) - (3, 5)
pop() 5 (3)
push(7) - (3, 7)
top() 7 (3, 7)
isEmpty() false (3, 7)
pop() 7 (3)
pop() 3 ()
pop() "error" ()

자바는 유틸 패키지로 스텍을 지원하기에,

import java.util.Stack; 을 통해 java에서 지원해주는 Stack 자료구조를 사용할 수 있습니다.

하지만 지금은 학습하는 시간이니 Array구조로 된 Stack을 조금 더 공부해보도록 하겠습니다.

* Stack interface

1
2
3
4
5
6
7
public interface Stack {
    public int size();
    public boolean isEmpty();
    public char top();
    public char push(char o);
    public char pop();
}
cs

 

3) Array-based Stack 

JAVA_STACK

</alt="JAVA_STACK"p>

위 그림을 예시로 1차원 배열 기반 Stack의 push, pop, size, top에 대하여 알아보겠습니다.

(Stack뿐만 아니라 컴퓨터 자료구조는 0부터 시작함을 유념해야 합니다.)

1차원 배열 Stack은 N을 사이즈로 하는 Array-List를 먼저 선언하여야 합니다.

그리고 Stack에 push될 때마다 element는 0에서부터 N-1까지 자리잡게 됩니다.

반대로 pop될 때는 현재 top의 위치에서 0까지 자료구조에서 빠져나가게 됩니다.

따라서 현재 ArrayList에 Stack이 얼마나 차지하였는지 알기위하여 top의 위치를 반드시 알고있어야 합니다.

top의 위치를 알면 그 다음에 push, pop의 위치를 알 수 있고 Stack의 size도 알 수 있습니다. size = t+1

(Stack이 N-1의 자리까지 모두 차 있을 때 push를 입력한다면 FullStackException, Stack이 현재 비어져있는 상태인데 pop을 입력한다면 EmptyStackException등의 예외처리를 통해 더 좋은 코드를 만들 수 있습니다.)


따라서 Array 기반 Stack을 구축할 때 우리는 처음에 Array의 size를 어떻게 설정할지 고민하여야 합니다.

처음부터 너무 큰 크기의 size를 잡을 경우 메모리 낭비가 심하게 되고,

적은 크기의 size를 잡게 된다면 금방 Stack이 가득 차버려 Resize해줘야하는 번거로움이 생깁니다.


Array-based Stack JAVA Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class ArrayStack implements Stack {
    private char[] data;
    private int top;
 
 
    public ArrayStack(int size){
        this.data = new char[size];
        this.top = -1;
    }
 
    public int size() {
        return this.top +1;
    }
 
    public boolean isEmpty() {
        return (this.top == -1);
    }
 
    public char top() {
        return this.data[this.top];
    }
 
    public char push(char o) {
        this.top++;
        this.data[this.top] = 0;
        return 0;
    }
 
    public char pop() {
        char returnC = this.data[this.top];
        this.top--;    
         return returnC;
    }
}
cs



4) Linked-List Stack

*Node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Node {
    private Object data;
    private Node nextNode;
    
    public Node(Object data){
    this.data = data;
    this.nextNode = null;
    }
    
    public void linkNode(Node top){
    this.nextNode = top;
    }
    
    public Object getData(){
    return this.data;
    }
    
    public Node getNextNode(){
    return this.nextNode;
    }
}
cs

Linked-List를 활용하여 Stack을 구현할 경우 1차원 배열 기반 Stack에서 가졌던 문제점을 해결할 수 있습니다.

메모리 걱정과 Stack의 용량 걱정을 하지 않는다는 장점을 지닙니다.

연결리스트에서 Stack은 header와 top으로 표현될 수 있습니다.

Stack LinkedList

초기의 header와 top은 아무런 node도 가르키고 있지 않습니다.

이후 첫 번째로 node가 추가되면(push) header와 top모두 push된 node를 가르키게 됩니다.

다음 node가 추가 될 때에는 top은 추가된 node를 가르키고 header는 꼬리에 꼬리를 무는 식으로 가르키게 됩니다.

이후 node가 삭제되면(pop) top과 삭제된 node의 연결관계를 끊고, 이전 header의 node를 가르키게 됩니다.

 

Linked-List Stack Push&Pop

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void push(Object item){
    Node newNode = new Node(item);
    newNode.linkNode(top);
    top = newNode;
}
 
public Object pop(){
    if(isEmpty()) {
        return 0// throw Exception
    }
    else{
        Object item = peek();
        top = top.getNextNode();
        return item;
    }
}
cs

 

5) Parentheses Matching

Stack을 이용하여 괄호 짝 검사를 할 수 있습니다.

괄호 열을 지나며 열린괄호는 stack에 push하고, 닫힌 괄호가 만났을 때 stack을 pop한 후 그 타입을 확인하여 줍니다.

즉, 괄호 짝 검사에서 Stack에 가장 최근에 들어간 열린 괄호와 현재 들어가는 닫힌 괄호는 같은 타입이어야 합니다.

  1. { ( [ ] ) }

  2. ( ( ) ) ) { ( ) }

  3. ( { ( ) ] )

  4. { ( ) } [

2번의 경우는 소괄호의 open이 없고, 3번의 경우는 괄호가 맞지 않으며, 4번의 경우는 대괄호의 close가 없습니다.

따라서 1번을 제외하고 모두 Incorrect Parentheses Matching입니다.


!) Case1. Stack Example

더보기

괄호 열 : { ( [ ] ) }

괄호 수행되는 Operation Stack
{ S.push( { ) ( { )
( S.push( ( ) ( { , ( )
[ S.push( [ ) ( { , ( , [ )
] S.pop() ( { , ( )
) S.pop() ( { )
} S.pop() -

Stack이 비어져있는데 pop 명령이 날 경우 : 2번 에러

Stack에서 pop된 결과가 괄호와 타입이 다를 경우 : 3번  에러

괄호 순회가 끝났음에도 불구하고 Stack에 element가 남아있는 경우 : 4번 에러

등의 방식으로 Stack을 활용하여 괄호쌍검사를 진행할 수 있습니다.

Stack : Parentheses Matching Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// importe java.util.Stack
// 혹은 Stack 직접 구현
 
public class pM {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String input = sc.nextLine();
        Stack stack = new Stack(input.length());
 
        // 괄호 열 Count
        int Count = 0
        for (Count = 0; loopCount < input.length(); Count++) {
            char ch = input.charAt(Count);
            // isIncorrect = true라면 괄호 짝 매칭 실패
            boolean isIncorrect = false;
 
            switch (ch) {
            
            //open 괄호일 경우 stack에 push합니다.
            case '('case '{'case '[':
                stack.push(ch);
                break;
 
            case ')':
                if (stack.isEmpty() || (ch = stack.pop()) != '(') {
                    isIncorrect = true// 2,3번 경우의 error
                }
                break;
 
            case '}':
                if (stack.isEmpty() || (ch = stack.pop()) != '(') {
                    isIncorrect = true// 2,3번 경우의 error
                }
                break;
 
            case ']':
                if (stack.isEmpty() || (ch = stack.pop()) != '(') {
                    isIncorrect = true// 2,3번 경우의 error
                }
                break;
            }
            
            // isIncorrect가 true일 경우 괄호짝 매칭 실패
            if(isIncorrect) {
                break;
            }
        }
        
        if(stack.isEmpty() && loopCount == input.length()) {
            System.out.println("correct");
        }
        
        else {
            System.out.println("incorrect"); // 4번 경우의 error
        }
    }
}
cs
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기