[ 자료구조 ] 스택구현

최수정·2022년 9월 28일
0

자바프로그래밍

목록 보기
1/15

개념

후입선출

  • 함수에서 함수를 호출하는 기능을 구현 하기 위해 stack()이 나왔다

실현코드

Main() 이전

    import java.util.Scanner;
    
    interface Stackable {
    	public boolean isEmpty();
    
    	public boolean isFull();
    
    	public void push(char item);
    
    	public char pop();
    
    	public char peek();
    
    	public void clear();
    }
    
    class Stack implements Stackable {
    	public int top;
    	public int stackSize;
    	public char stackArr[];
    
    	// 스택을 생성한다.
    	public Stack(int stackSize) {
    		top = -1; // 스택 포인터 초기화
    		this.stackSize = stackSize; // 스택 사이즈 설정
    		stackArr = new char[this.stackSize]; // 스택 배열 생성
    	}
    
    	@Override
    	public boolean isEmpty() {
    		if (this.top == -1) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public boolean isFull() { // 1을 빼준 이유는 인덱스 특성때문에.
    		if (this.top == (this.stackSize - 1)) {
    			return true;
    		}
    		return false;
    	}
    
    	@Override
    	public void push(char item) {
    		if (isFull()) {
    			System.out.println("스택이 이미 가득 찼어요");
    		} else {
    			stackArr[++top] = item;
    			System.out.println("입력된 문자: " + item);
    		}
    	}
    
    	@Override
    	public char pop() {
    		if (isEmpty()) {
    			System.out.println("스택은 이미 비어있어요");
    			return 0;
    		} else {
    			System.out.println("삭제된 문자: " + stackArr[top]);
    			return stackArr[top--]; // 포인터 이동?
    		}
    	}
    
    	@Override
    	public char peek() {
    		if (isEmpty()) {
    			System.out.println("스택은 이미 비어있어요");
    			return 0;
    		} else {
    			System.out.println("엿볼려는 문자: " + stackArr[top]);
    			return stackArr[top];
    		}
    	}
    
    	@Override
    	public void clear() { //
    		if (isEmpty()) {
    			System.out.println("이미 비어있습니다.");
    		} else {
    			for (int i = top; i > -1; i--) {
    				stackArr[i] = 0;
    			}
    			top = -1;
    			System.out.println("스택이 초기화 됐습니다.");
    			// stackArr = new char[this.stackSize];
    			// 스택 배열 다시생성하는 것보다 배열 안의 값을 초기화하고 값을 다시 채울 수 있게 포인터만 변경하는 방법으로 채택
    		}
    	}
    
    	// 스택에 저장된 모든 데이터를 출력
    	public void printStack() {
    		if (isEmpty()) {
    			System.out.println("스택에 아무것도 없어요!");
    		} else {
    			System.out.print("Stack elements : ");
    
    			for (int i = 0; i <= top; i++) {
    				System.out.print(stackArr[i] + " ");
    			}
    			System.out.println();
    		}
    	}
    }

main()

    public class StackTest {
    
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		System.out.print("스택 사이즈를 입력하시오.");
    		int stackSize = sc.nextInt();
    
    		Stack stack = new Stack(stackSize);
    
    		stack.push('A');
    		stack.printStack();
    
    		stack.push('B');
    		stack.printStack();
    
    		stack.push('C');
    		stack.printStack();
    
    		stack.pop();
    		stack.printStack();
    
    		stack.pop();
    		stack.printStack();
    
    		stack.peek();
    		stack.printStack();
    
    		stack.clear();
    		stack.printStack();
    
    	}
    
    }

🚨 디버그 사항

NullPointerException

🔽 에러 뜬 부분의 코드

@Override
	public boolean isFull() { 
		if (this.top == ( stackArr.length - 1)) { return true; }
		return false;
	}
  • NullPointerException은 RuntimeException이다. 프로그램에 null값을 가지는 객체 참조를 사용하려고 하면 NullPointerException이 throw 된다. 에러에 대한 설명을 보니, 모든 참조유형에 대한 기본 값이 null이라는걸 생각해 보면, 내가 객체.메서드를 사용한 부분에서 에러가 난것으로 보아 객체 생성이 제대로 되지 않았나? 하는 의문점이 들었다.
    • 실제로 구글링을 해보니 이 예외가 발생하는 경우로는,
      1. null 객체에서 method를 호출하는 경우
      2. null 객체의 필드에 접근하거나 값을 변경하는 경우
      3. null의 길이를 배열처럼 취하는 경우
      4. null을 throw하는 경우
      5. null을 통해 동기화 할 경우
public Stack(int stackSize) {
        top = -1;    // 스택 포인터 초기화
        this.stackSize = stackSize; // 스택 사이즈 설정
        stackArr = new char[this.stackSize]; // 스택 배열 생성
    }

@Override
	public boolean isFull() { 
		if (this.top == ( stackArr.length - 1)) { return true; }
		return false;
	}

알고보니, 4번째 줄의 배열 생성이 빠져 있어서 난 오류였다. 결국 배열을 생성하지도 않아놓고 배열의 참조변수인 stackArr을 이용해 stackArr.length을 코딩해 벌어진 참사였다.


else의 생략

🔽 코드

public void printStack() {
		if (isEmpty()) {
			System.out.println("스택에 아무것도 없어요!");
		} 
		System.out.print("Stack elements : ");
		
		for (int i = 0; i <= top; i++) {
			System.out.print(stackArr[i] + " ");
		}
		System.out.println();
	}
  • 설명 inEmpty()문을 통해 배열이 비어있다면 스택에 아무것도 없다고 출력한 뒤 끝나야 하는데, 그 뒤에 inEmpty()문을 통해 배열이 비어있다면 스택에 아무것도 없다고 출력한 뒤 끝나야 하는데, 그 뒤에 "Stack elements : " 문구까지 출력이 되어서 의도와 다르게 프로그래밍 되었다. 문제점은 else의 생략이 가능한 경우는 정해져 있단 걸 간과했다. 함수 안에서 return 을 사용하거나, 반복문 안에서 break continue 를 사용할 때 else 의 생략이 가능하다. printStack함수는 void형으로 정하고 만들었음으로, retrun을 사용할 수는 없으니 else를 꼭 넣어주어야 한다.
    • 반환형메서드의 경우, if문 안에 return 0; 을 해주면 프로그램이 정상종료된다는 것도 알아두자.
      @Override
      	public char pop() {
      		if (isEmpty()) {
      			System.out.println("스택은 이미 비어있어요");
      			return 0;  // 스택은 이미 비어있으니 할게 없어 프로그램 종료.
      		} else {
      		System.out.println("삭제된 문자: " + stackArr[top]);
      		return stackArr[top--]; // 포인터 이동?
      	}
      }

🔽 수정 후 정상코드

public void printStack() {
		if (isEmpty()) {
			System.out.println("스택에 아무것도 없어요!");
		} else {
			System.out.print("Stack elements : ");

			for (int i = 0; i <= top; i++) {
				System.out.print(stackArr[i] + " ");
			}
			System.out.println();
		}
	}

참고

증감연산자

0개의 댓글