[자료구조] Stack

스택은 삽입과 삭제가 한쪽 끝에서 이루어지는, 순서가 매겨진 리스트이다. 이 끝을 탑(top)이라고 부른다. 제일 마지막에 추가된 항목이 제일 먼저 삭제된다. 그러므로 후입선출(LIFO) 혹은 선입후출(FILO) 리스트라고 불린다.

push() - 스택에 항목 삽입

pop() - 항목을 스택으로부터 삭제

underflow - 빈 스택으로부터 항목을 팝하려는 것

overflow - 가득 찬 스택에 항목을 푸시하려는 것

적용사례

간단한 배열에 기반한 구현

    public class ArrayStack{
    	private int top;
    	private int capacity;
    	private int[] array;
    	public ArrayStack(){
    		capacity = 10;
    		array = new int[capacity];
    		top = -1;
    	}
    	public boolean isEmpty(){
    		return (top == -1);
    	}
    	public boolean isStackFull(){
    		return (top == capacity - 1);
    	}
    	public void push(int data){
    		if(isStackFull()){
    			System.out.println("Stack Overflow");
    		} else {
    			array[++top] = data;
    		}
    	}
    	public int pop(){
    		if(isEmpty()){
    			System.out.println("Stack is Empty");
    			return 0;
    		} else {
    			return array[top--];
    		}
    	}
    }

push(), pop() 시간복잡도 O(1)

동적 배열에 기반한 구현

두 배 확장 방법으로.

    public class DynamicArrayStack{
    	private int top;
    	private int capacity;
    	private int[] array;
    	public DynamicArrayStack(){
    		capacity = 10;
    		array = new int[capacity];
    		top = -1;
    	}
    	public boolean isEmpty(){
    		return (top == -1);
    	}
    	public boolean isStackFull(){
    		return (top == capacity - 1);
    	}
    	public void push(int data){
    		if(isStackFull()){
    			doubleStack();
    		} else {
    			array[++top] = data;
    		}
    	}
    	public void doubleStack(){
    		int newArray[] = new int[capacity * 2];
    		System.arraycopy(array, 0, newArray, 0, capacity);
    		capacity = capacity * 2;
    		array = newArray;
    	}
    	public int pop(){
    		if(isEmpty()){
    			System.out.println("Stack is Empty");
    			return 0;
    		} else {
    			return array[top--];
    		}
    	}
    }

push() 시간복잡도 O(n) 확장 때문에. amortized O(1). pop() O(1)

연결 리스트 구현

가장 처음 노드 삽입, 삭제

    public class LLStack{
    	private Node head;
    	public LLStack(){
    		head = new Node(null);
    	}
    	public boolean isEmpty(){
    		if(head == null) return true;
    		else return false;
    	}
    	public boolean isStackFull(){
    		return (top == capacity - 1);
    	}
    	public void push(int data){
    		if(head == null){
    			head = new Node(data);
    		} else if(head.getData() == null) {
    			head.setData(data);
    		} else {
    			Node node = new Node(data);
    			node.setNext(head);
    			head = node;
    		}
    	}
    	public int pop(){
    		if(head == null){
    			System.out.println("Stack is Empty");
    			return 0;
    		} else {
    			int data = head.getData();
    			head = head.getNext();
    			return data;
    		}
    	}
    }

push(), pop() 시간복잡도 O(1)

배열 구현 vs 연결 리스트 구현

배열 구현

연결 리스트 구현

성능이 극도로 중요한 경우라면 적당히 큰 크기의 배열을 먼저 메모리에 올려두고 동적 배열로 구현할 것 같다. 배열 구현에서의 push(), pop()에서 연산처리속도가 아무래도 더 빠르기 때문이다.