본문 바로가기
프로그래밍 언어/자료구조 & 알고리즘

자료구조 - 순차리스트(1) 스택(Stack)

by Hyeon_ 2021. 11. 29.

자료구조(Data Structure)

자료구조 종류

  • 순차 리스트
    • 배열 / 행렬 / 레코드
    • 스택 / 큐 / 데크
  • 연결리스트
    • 단일 연결 리스트
    • 원형 연결 리스트
    • 이중 연결 리스트
  • 트리
    • 일반 트리
    • 이진 트리

순차 리스트

  • 각 자료가 메모리 중에서 서로 이웃해 있는 구조
  • 선형 구조라고도 함
  • 메모리에 연속적으로 저장
  • 종류
    • 배열 / 행렬 / 레코드
    • 스택 / 큐 / 데크

배열

  • 크기와 데이터형이 같으며 동일한 이름을 갖는 원소들의 연속적 저장공간
  • 배열의 원소는 메모리 내에서 연속적으로 순서대로 저장
  • 각 배열의 원소는 첨자(인덱스 [0]부터 시작)로 구별

레코드

  • 서로 다른 데이터 형태와 크기로 구성되어 있는 데이터 구조
  • 이질적 구조
  • ex)
    • 어떤 사람에 관한 자료들인 이름, 주민등록번호, 주소 등과 같이 서로 관계있는 여러 필드를 한 개의 조로 묶어서 구성
  • 배열과의 차이점
    • 배열: 데이터 원소의 크기와 데이터 형태 동일
    • 레코드: 데이터 원소의 크기와 데이터 형태 서로 다름

스택 (Stack)

  • 쌓아 올린 더미를 의미
  • 선형 리스트 구조의 특별한 형태
  • 리스트 내의 데이터 삽입과 삭제가 Top이라고 하는 한쪽 끝에서만 일어나는 데이터 구조
  • 데이터 구조에서는 기억 장치에 데이터를 일시적으로 쌓아 두었다가 필요할 때 꺼내서 사용할 수 있는 주기억장치(메모리)나 레지스터의 일부를 할당하여 사용하는 임시적인 기억을 말함
  • 푸시(push) / 팝(pop)의 이름으로 가장 마지막에 삽입한 데이터를 제일 먼저 삭제
  • LIFO(Last-In First-Out) / 후입선출방식

 

 

[출처: 

 

  • n: 스택 크기
    • 스택에 저장할 수 있는 최대 노드의 수
  • TOP: top point
    • 스택에 대한 삽입과 삭제가 이루어지는 위치
    • 가장 최근에 입력된 항목의 위치를 가리키는 포인터
    • 출력 우선 순위가 가종 높은 원소를 가리키는 포인터
    • 초기에 TOP은 0부터 시작
    • 주의!!
      • 배열로 스택 구현 시 배열 첨자가 0부터 시작하므로 TOP은 -1로 초기화
  • BOTTOM
    • TOP의 반대쪽으로 노드의 입출력 불가
  • PUSH: 삽입
    • 스택에 새로운 노드 입력
    • TOP = TOP + 1
  • POP: 삭제
    • 스택에서 노드 삭제
    • TOP = TOP - 1
  • 오버플로우(Overflow)
    • 스택이 가득 차있을 때 (TOP == n) 새로운 노드가 생기면 스택에 더 이상 삽입을 할 수 없는 경우
    • TOP > n
    • Full (스택에 삽입 전에 Overflow가 발생하는지(스택이 가득 차있는지) 확인: isfull())
  • 언더플로우(underflow)
    • 스택이 비어있을 때(TOP == 0) 노드의 삭제가 일어나서 더 이상 삭제를 할 수 없는 경우
    • TOP < 0
    • Empty (스택에서 노드 삭제 전에 underflow가 발생하는지(스택이 비어있는지) 확인: isEmpty())

스택에서 사용되는 연산

  • 삽입(push)
if TOP == n then overflow exist
TOP = TOP + 1
stack[TOP] <- insert_data
  • 삭제 (pop)
if TOP = 0 then underflow exist
deleted_data <- stack[TOP]
TOP = TOP -1

스택의 이용

  • 서브 프로그램의 복귀 주소(return address) 보관
  • 산술식 표현 : a + b
  • Java 프로그램에서 메서드 호출하고 실행할 때 스택 사용

힙 영역

  • JVM 시작할 때 생성
  • 객체 / 배열 저장
  • 사용되지 않는 객체는 Garbage Collector가 자동 제거

JVM 스택

  • 스레드 별 생성
  • 메서드 호출할 때마다 프레임(Frame)을 스택에 추가 (PUSH)
  • 메서드 종료하면 프레임 제거 (POP)
  • 프레임 내부의 로컬 변수 스택에 변수 저장
    • 변수에 값이 저장될 때 변수 생성

연습문제 - Stack

  • 스택(stack) 예제
    • 배열을 사용해서 스택 구현
    • java.util.Stack 클래스 이용
  • 배열을 사용해서 스택 구현
    • index가 0부터 시작하므로 초기 상태를 top = -1로 설정
    • top이 -1이면, empty, underflow
    • push 하려면 --top
    • pop은 top--
MyStack.java
package Stack;

public class MyStack {
    // 멤버 변수
    private int stackSize; // 스택 크기
    private int top; // 스택 포인터
    private char[] stackArr; // 스택(배열) : 배열 변수만 선언. 아직 할당되지 않음

    // 생성자: 스택 초기화
    // 배열 인덱스는 0부터 시작
    // top 초기화는 -1로 설정

    public MyStack(int stackSize) {
        top = -1;
        this.stackSize = stackSize; // 스택 크기 설정
        stackArr = new char[this.stackSize]; // 스택 배열 생성
    }

    // 메서드

    // 스택이 비었는지 확인하는 isEmpty()
    // 결과 반환: true / false
    public boolean isEmpty() {
        return top == -1; // top이 -1이면 true, 아니면 false 반환
    }

    // 스택이 가득 차있는지 확인하는 isFull()
    // 결과 반환: true / false
    // 가득 찬 상태: top이 4인 경우, (즉, stackSize -1)
    // stackSize: 5
    // 스택 index: 0,1,2,3,4
    public boolean isFull() {
        return top == stackSize-1;
    }

    // 스택에 데이터 삽입하는 push()
    // (1) 삽입 전에 Overflow 발생하는지 확인: isEmpty() 호출해서 결과 받아서 확인
    // (2) Full이 아니면 top을 하나 증가한 위치에 데이터 삽입 ++top
    // 삽입하기 위해 데이터 매개변수 받음
    // 직접 스택에 삽입하고 종료 -> 반환값 없음
    public void push(char item) {
        if(isFull()) {
            System.out.println("Stack Full. Overflow");
        }
        else{
            // 초기값이 -1이므로, push 할 때 먼저 1 증가
            stackArr[++top] = item;
        }
    }

    // 스택에 데이터를 삭제하는 pop()
    // Empty가 아니면 top 위치에 있는 데이터 삭제
    // 삭제 후 top 1 감소시켜 :top--
    //
    public char pop() {
        if(isEmpty()) {
            System.out.println("Stack Empty. UnderFlow");
            return 'E'; // 형식적인 return 값
        }
        else{
            // top 위치에 있는 데이터 반환하고 top을 1 감소시킴
            return stackArr[top--];
        }
    }

    // 스택의 최상위 데이터를 출력하는 peek()
    // (1) 먼저 스택이 비었는지 확인
    // (2) 최상위 데이터 (top 위치에 있는 데이터) 반환
    // 최상위 데이터(문자) 반환하므로 반환형 있음
    public char peek() {
        if(isEmpty()){
            System.out.println("Stack Empty");
            return 'E';
        }
        else{
            // 현재 최상위 위치(top의 위치)의 값 반환
            return stackArr[top];
        }
    }

    // 스택의 내용을 비우는 clear()
    public void clear() {
        top = -1;
    }

    // 스택의 전체 데이터를 출력하는 showStack()
    // 출력만 하고 반환값 얻음
    // 먼저 출력하지 전에 스택이 비었는지 확인
    // 스택에 있는 모든 요소의 값 출력 (배열의 모든 요소의 값 출력)
    public void showStack() {
        if(isEmpty()) {
            System.out.println("Stack Empty");
        }
        else {
            System.out.print("Stack items: ");
            for(int i = 0; i <= top; i++){
                System.out.print(i + ":" + stackArr[i] + " ");
            }
            System.out.println("\ntop : "+ top);
        }
    }
}
MyStackMain.java
package Stack;

public class MyStackMain {
    public static void main(String[] args) {
        // 스택 크기 설정
        int stackSize = 5;
        MyStack stk = new MyStack(stackSize);

        System.out.print("Stack 초기 상태: ");
        stk.showStack();

        System.out.println("\npop 수행");
        stk.pop();

        System.out.println("\na, b, c push 수행");
        stk.push('a');
        stk.push('b');
        stk.push('c');
        stk.showStack();

        System.out.println("\n최상위 값: " + stk.peek());

        System.out.println("\nd, e push 수행");
        stk.push('d');
        stk.push('e');
        stk.showStack();

        System.out.println("\nf push 수행");
        stk.push('f');

        System.out.println("\npop 2번 수행");
        System.out.println("pop한 값: "+stk.pop());
        System.out.println("pop한 값: "+stk.pop());
        stk.showStack();

        System.out.println("\nclear 수행");
        stk.clear();
        stk.showStack();
    }
}
[OUTPUT]
Stack 초기 상태: Stack Empty

pop 수행
Stack Empty. UnderFlow

a, b, c push 수행
Stack items: 0:a 1:b 2:c 
top : 2

최상위 값: c

d, e push 수행
Stack items: 0:a 1:b 2:c 3:d 4:e 
top : 4

f push 수행
Stack Full. Overflow

pop 2번 수행
pop한 값: e
pop한 값: d
Stack items: 0:a 1:b 2:c 
top : 2

clear 수행
Stack Empty
StackTest.java (java.util.Stack 사용)
package Stack;

import java.util.Stack;

public class StackTest {
    public static void main(String[] args) {
        Stack<String> stk = new Stack<String>();

        stk.push("홍길동");
        stk.push("이몽룡");
        stk.push("성춘향");

        for(int i = 0; i < stk.size(); i++) {
            System.out.println(i + ": " + stk.get(i));
        }

        System.out.println("스택 크키: "+ stk.size());
        System.out.println("최상위 값: "+stk.peek());
        System.out.println("이몽룡 들어 있는가? : "+stk.contains("이몽룡"));
        System.out.println("pop 수행: "+stk.pop());

        for(int i = 0; i<stk.size(); i++){
            System.out.println(i + " : "+ stk.get(i));
        }

        System.out.println("clear 수행");
        stk.clear();
        System.out.println("empty? : "+ stk.empty());
    }
}
[OUTPUT]
0: 홍길동
1: 이몽룡
2: 성춘향
스택 크키: 3
최상위 값: 성춘향
이몽룡 들어 있는가? : true
pop 수행: 성춘향
0 : 홍길동
1 : 이몽룡
clear 수행
empty? : true