1. Stack이란?

스택

  • 마지막에 들어온 데이터가 가장 먼저 나간다. 즉, 후입선출(LIFO) 방식이다.
  • 맨 위의 원소에만 접근이 가능하다. 
  • 가상 메모리의 스택 영역에서 이와 같은 자료 구조를 이용한다.

cf) 연결리스트로 스택 구현하기

연결리스트로 스택을 구현은 위처럼 topNode를 두고 새로운 데이터가 추가될 때마다 해당 노드를 topNode로 설정한 뒤 이전 노드를 참조하는 방식으로 이루어진다. 삭제할 땐 topNode.next를 topNode로 설정해주면 된다.

 

2. Stack 구현하기

구현할 내용은 아래와 같다.

  • push(E x) - 원소 x를 스택에 입력한다.
  • pop() - 스택 맨 위의 원소를 삭제한다.
  • top() - 스택 맨 위의 원소 값을 리턴한다.
  • isEmpty() - 스택이 비었는지 여부를 리턴한다.
  • popAll() - 스택의 내부 데이터를 모두 삭제한다.
  • printAll() - 스택의 내부의 모든 데이터를 출력한다.

** 원래 스택에서는 맨 위의 값에만 접근이 가능하나, 테스트 편의상 printAll() 메서드를 만들어 사용하였다.

 

1) 노드 클래스

public class Node<E> {

	public E item;
	public Node<E> next;
	
	public Node (E newItem) {
		item = newItem;
		next = null;
	}
	
	public Node (E newItem, Node<E> nextNode) {
		item = newItem;
		next = nextNode;
	}
}
  • item 변수에 데이터를 저장한다.
  • next 변수에 다음 노드를 저장한다. next는 다음 노드의 위치를 가리키는 포인터가 된다.
  • 첫 번째 생성자는 데이터를 입력받아 데이터를 item에 저장하고, 포인터 값은 null로 저장한다.
  • 두 번째 생성자는 데이터와 다음 노드를 입력받아 데이터를 item에 저장하고, 포인터 값에 다음 노드를 저장한다.

 

2) 인터페이스

public interface StackInterface<E> {

	public void push (E x);
	
	public void pop();
	
	public E top();
	
	public boolean isEmpty();
	
	public void popAll();
	
	public void printAll();
	
}

 

3) LinkedStack 클래스

<push 메서드 구현>

@Override
	public void push(E x) {
		topNode = new Node<> (x, topNode);
		
	}
  • 기존 topNode를 다음 노드로 참조하고 입력 받은 값을 item 값으로 하는 새 노드를 만든다.

<pop 메서드 구현>

@Override
	public void pop() {
		if (isEmpty()) {
			System.out.println("ERROR");
	} else {
		topNode = topNode.next;
		}
	}
  • 스택이 비었다면 에러를 출력한다.
  • 그렇지 않다면 기존 topNode 자리에 기존 topNode가 참조하던 다음 노드가 들어오게 한다.

<top 메서드 구현>

@Override
	public E top() {
		if (isEmpty()) {
			return null;
		} else {
			return topNode.item;
		}
	}
  • 스택이 비었다면 null 값을 리턴한다.
  • 그렇지 않다면 topNode의 item값을 리턴한다.

<isEmpty 메서드 구현>

@Override
	public boolean isEmpty() {
		return topNode==null;
	}
  • topNode가 null값인지 여부를 리턴한다.

<popAll 메서드 구현>

@Override
	public void popAll() {
		topNode = null;	
	}
  • topNode를 null로 초기화한다.

<printAll 메서드 구현>

@Override
	public void printAll() {
		Node<E> currNode = topNode;
		while (currNode!=null) {
				System.out.print(currNode.item+" ");
				currNode=currNode.next;
		}
  • for문이 topNode부터 스택의 전체 노드를 순회하며 값을 프린트한다.

- 전체 코드

public class LinkedStack<E> implements StackInterface<E>{

	private Node<E> topNode;
	
	public LinkedStack() {
		topNode=null;
	}
	
	@Override
	public void push(E x) {
		topNode = new Node<> (x, topNode);
		
	}

	@Override
	public void pop() {
		if (isEmpty()) {
			System.out.println("ERROR");
	} else {
		topNode = topNode.next;
		}
	}
	
	@Override
	public E top() {
		if (isEmpty()) {
			return null;
		} else {
			return topNode.item;
		}
	}

	@Override
	public boolean isEmpty() {
		return topNode==null;
	}

	@Override
	public void popAll() {
		topNode = null;
		
	}

	@Override
	public void printAll() {
		Node<E> currNode = topNode;
		while (currNode!=null) {
				System.out.print(currNode.item+" ");
				currNode=currNode.next;
		}
		
	}

}

** 배열 리스트로 구현한 스택과 달리 정해진 용량이 없기 때문에 isFull 메서드는 필요하지 않다.

 

3) 결과 확인하기

<코드>

public class Test {
	public static void main(String[] args) {

	LinkedStack<Integer> stack = new LinkedStack<>();
	
	stack.push(100);
	
	stack.push(200);
	
	stack.push(300);
	
	stack.push(400);
	
	System.out.println(stack.top());
	
	stack.printAll();
	System.out.println();
	
	
	for (int i=0; i<5; i++) {
		stack.pop();
	}
	
	stack.printAll();
	
	//스택에서 pop을 5번 수행한 뒤 출력합니다. - 원소가 4개인데 5번 pop하였으므로 에러가 발생하고, 스택이 비어있으므로 내용물은 출력되지 않음.
	
	System.out.println(stack.isEmpty());
	
	// 스택이 비었는지 여부를 출력합니다.
	
	stack.push(100);
	stack.printAll();
	System.out.println();
	
	//stack에 100을 입력하고 출력합니다.
	
	stack.popAll();
	stack.printAll();
	
	//stack에 - stack을 popAll 했으므로 내용물이 출력되지 않음.
	
	}
}

<결과>

1. Stack이란?

스택

  • 마지막에 들어온 데이터가 가장 먼저 나간다. 즉, 후입선출(LIFO) 방식이다.
  • 맨 위의 원소에만 접근이 가능하다. 
  • 가상 메모리의 스택 영역에서 이와 같은 자료 구조를 이용한다.

2. Stack 구현하기

구현할 내용은 아래와 같다.

  • push(E x) - 원소 x를 스택에 입력한다.
  • pop() - 스택 맨 위의 원소를 삭제한다.
  • top() - 스택 맨 위의 원소 값을 리턴한다.
  • isEmpty() - 스택이 비었는지 여부를 리턴한다.
  • popAll() - 스택의 내부 데이터를 모두 삭제한다.
  • printAll() - 스택의 내부의 모든 데이터를 출력한다.

** 원래 스택에서는 맨 위의 값에만 접근이 가능하나, 테스트 편의상 printAll() 메서드를 만들어 사용하였다.

 

1) 인터페이스

public interface StackInterface<E> {

	public void push (E x);
	
	public void pop();
	
	public E top();
	
	public boolean isEmpty();
	
	public void popAll();
	
	public void printAll();
	
}

 

2) 클래스

- 필드 영역

//필드 영역
	private E stack[];
	private int topIndex;
	private static final int DEFAULT_CAPACITY = 64;
  • stack - 원소를 입력 받을 배열 리스트이다.
  • topIndex - 스택의 맨 윗 원소의 인덱스를 저장한다.
  • DEFAULT_CAPACITY - 스택 생성 시 용량을 따로 선언하지 않을 경우 설정할 기본 용량이다.

- 생성자 영역

//생성자 영역
	public ArrayStack() {
		stack = (E[]) new Object[DEFAULT_CAPACITY];
		topIndex = -1;
	}
	
	public ArrayStack(int n) {
		stack = (E[]) new Object[n];
		topIndex = -1;
	}
  • 생성 시 입력 값으로 정수를 받으면 해당 정수 크기의 스택을, 그렇지 않으면 DEFAULT_CAPACITY 크기의 스택을 생성한다.

-메서드 영역

<push 메서드 구현>

//메서드 영역
	@Override
	public void push(E x) {
		if (isFull()) {
			System.out.println("ERROR");
		} else {
			topIndex++;
			stack[topIndex]=x;
		}
	}
  • 만약 stack에 남은 공간이 없는데 push를 시도하면 에러를 출력한다.
  • 그렇지 않으면 topIndex를 늘려준 뒤 해당 인덱스에 입력받은 데이터를 입력한다.

<pop 메서드 구현>

@Override
	public void pop() {
		if (isEmpty()) {
			System.out.println("ERROR");
		} else {
		stack[topIndex]=null;
		topIndex--;
		}
	}
  • 만약 stack이 비어 있는데 pop을 시도하면 에러를 출력한다.
  • 그렇지 않다면 현재 topIndex를 null로 바꾼 후 topIndex를 1 감소시킨다.
  • ** 사실 add시 해당 인덱스를 덮어 쓸 것이기 때문에 topIndex만 1 감소시키고 null 처리는 해주지 않아도 된다.

<top 메서드 구현>

@Override
	public E top() {
		if (isEmpty()) {
			return null;
		} else {
		return stack[topIndex];
		}
	}
  • 만약 스택이 비어있는데 top을 시도하면 null 값을 반환한다.
  • 그렇지 않다면 stack의 topIndex값을 반환한다.

<isEmpty&isFull 메서드 구현>

@Override
	public boolean isEmpty() {
		return (topIndex<0);
	}

//isFull메서드는 인터페이스를 오버라이딩 한 것이 아님에 주의!
	public boolean isFull() {
		return (topIndex==stack.length-1);
	}
  • isEmpty - topIndex가 음수이면 true, 아니면 false.
  • isFull - topIndex와 스택의 크기를 비교하여 스택이 다 찼는지를 판별.

<popAll 메서드 구현>

@Override
	public void popAll() {
		stack = (E[]) new Object[stack.length];
		topIndex=-1;
	}
  • stack을 기존 길이의 빈 배열 리스트로 덮어쓴다.
  • topIndex를 초기화한다.

<printAll 메서드 구현>

@Override
	public void printAll() {
		
		for (int i=0; i<=topIndex; i++) {
			System.out.print(stack[i]+" ");
		}
		
	}
  • for문이 전체 스택의 인덱스를 순회하며 해당 인덱스의 값들을 프린트한다.

- 전체 코드

public class ArrayStack<E> implements StackInterface<E> {
	
	//필드 영역
	private E stack[];
	private int topIndex;
	private static final int DEFAULT_CAPACITY = 64;
	
	//생성자 영역
	public ArrayStack() {
		stack = (E[]) new Object[DEFAULT_CAPACITY];
		topIndex = -1;
	}
	
	public ArrayStack(int n) {
		stack = (E[]) new Object[n];
		topIndex = -1;
	}
	
	//메서드 영역
	@Override
	public void push(E x) {
		if (isFull()) {
			System.out.println("ERROR");
		} else {
			topIndex++;
			stack[topIndex]=x;
		}
	}

	@Override
	public void pop() {
		if (isEmpty()) {
			System.out.println("ERROR");
		} else {
		stack[topIndex]=null; //안해도 됨.
		topIndex--;
		}
	}

	@Override
	public E top() {
		if (isEmpty()) {
			return null;
		} else {
		return stack[topIndex];
		}
	}

	@Override
	public boolean isEmpty() {
		return (topIndex<0);
	}

	public boolean isFull() {
		return (topIndex==stack.length-1);
	}

	@Override
	public void popAll() {
		stack = (E[]) new Object[stack.length];
		topIndex=-1;
	}

	@Override
	public void printAll() {
		
		for (int i=0; i<=topIndex; i++) {
			System.out.print(stack[i]+" ");
		}
		
	}

}

3) 결과 확인하기

<코드>

public class Test {
	public static void main(String[] args) {

	ArrayStack<Integer> stack = new ArrayStack<>();
	
	stack.push(100);
	
	stack.push(200);
	
	stack.push(300);
	
	stack.push(400);
	
	System.out.println(stack.top());
	
	stack.printAll();
	System.out.println();
	
	
	
	for (int i=0; i<5; i++) {
		stack.pop();
	}
	
	stack.printAll();
	
	//스택에서 pop을 5번 수행한 뒤 출력합니다. - 원소가 4개인데 5번 pop하였으므로 에러가 발생하고, 스택이 비어있으므로 내용물은 출력되지 않음.
	
	System.out.println(stack.isEmpty());
	
	// 스택이 비었는지 여부를 출력합니다.
	
	stack.push(100);
	stack.printAll();
	System.out.println();
	
	//stack에 100을 입력하고 출력합니다.
	
	stack.popAll();
	stack.printAll();
	
	//stack에 - stack을 popAll 했으므로 내용물이 출력되지 않음.
	
	}
}

<결과>

정상적으로 출력된다.

+ Recent posts