Computer Science/자료구조

[5.11] 04 스택과 큐

토마토. 2021. 5. 11. 21:18

<Do it! 자료구조와 함께 배우는 알고리즘 입문>

04-1 스택이란? 

스택 알아보기

stack : LIFO 후입선출 last in first out 방식의 자료구조

push 데이터 넣기

pop 데이터 꺼내기

top 윗부분

bottom 아랫부분

 

스택 구현하기

스택 배열 stk - 스택 본체 list형 배열

: stk[0] 스택의 buttom

스택 크기 capcity - len(stk)

스택 포인터 : stack pointer - 데이터의 개수를 나타내는 정숫값

cf) from enum import Enum : 열거형 enumeration 지원

 

스택 클래스

- 예외 처리 클래스 Empty

    class Empty(Exception):
        pass

- pop, peek를 할 때 쓰임. 

    elif menu == Menu.팝:
        try:
            x = s.pop()
            print(f'팝한 데이터는 {x}입니다.')
        except FixedStack.Empty:
            print('스택이 비어있습니다.')
    elif menu == Menu.피크:
        try:
            x = s.peek()
            print(f'피크한 데이터는 {x}입니다.')
        except FixedStack.Empty:
            print('스택이 비어있습니다.')

- 예외 처리 클래스 Full

- 비슷한 기능으로 push()에서 쓰임

- __init__()

초기화하는 기능임.

매개변수 capacity를 전달받아 리스트 stk 생성

스택의 크기 capacity로 복사

이때 포인터 ptr의 값은 0

    def __init__(self, capacity: int = 256) -> None:
        self.stk = [None] * capacity
        self.capacity = capacity
        self.ptr = 0

- __len__() 함수

쌓여있는 데이터의 개수는? 

    def __len__(self) -> int:
        return self.ptr

- is_empty(), is_full()

__init__()에서 ptr = 0으로 할당함. 따라서 ptr <= 0 일 때 empty

스택의 크기 = capacity이므로 ptr >= capacity일 때 full

    def is_empty(self) -> bool:
        return self.ptr <= 0
    def is_full(self) -> bool:
        return self.ptr >= self.capacity

* cf) 예외처리 기본 구조 try statement

try:

except :

else:

finally: 

- push() 데이터를 푸시

좀아까 정의한 self.is_full()인 경우에는 FixedStack.Full로 예외처리한다. 

그렇지 않은 경우에는

self.stk 리스트의 ptr 포인터 위치에 전달받은 value를 저장하고

포인터를 1 증가시킨다. 

    def push(self, value: Any) -> None:
        if self.is_full():
            raise FixedStack.Full
        self.stk[self.ptr] = value
        self.ptr += 1

- pop()

꺼낼 데이터가 없은 경우 self.is_empty() -> FixedStack.Empty를 불러내어 pass

        except FixedStack.Empty:
            print('스택이 비어있습니다.')

패스한 뒤에는 이렇게 인식해서 출력함. 

원래 작업하려고 다음 위치에 ptr가 설정된 것을 -1 줄인 다음에

그 위치의 리스트값을 반환한다. 

self.stk[self.ptr]

    def pop(self) -> Any:
        if self.is_empty():
            raise FixedStack.Empty
        self.ptr -= 1
        return self.stk[self.ptr]

- peek()

비어있지 않으면 ptr 값을 수정하지 않은 채로 ptr-1의 리스트값 반환

    def peek(self) -> Any:
        if self.is_empty():
            raise FixedStack.Empty
        return self.stk[self.ptr -1]

- clear()

 

* cf) raise statement 를 통한 예외처리

표준 내장 예외 처리 ValueError class, ZeroDivisionError class etc..

사용자 정의 예외 처리...

 

- find()

스택에서 value가 들어있는지 검색한다. 포인트값에서 -1까지 -1씩 작아지는 방향으로 찾는다. 

찾지 못하면 -1 반환

    def find(self, value:Any) -> Any:
        for i in range(self.ptr -1, -1, -1):
            if self.stk[i] == value:
                return i
        return -1

- count()

데이터의 개수를 반환. 

    def count(self, value:Any) -> bool:
        c = 0
        for i in range(self.ptr):
            if self.stk[i] == value:
                c += 1
        return c

- __contains__()

bool 형태(True/False) 출력. 

    def __contains__(self, value:Any) -> bool:
        return self.count(value)

- dump()

비어있지 않으면, stk 전체를 출력한다. 

    def dump(self)-> None:
        if self.is_empty():
            print('스택이 비어있습니다.')
        else:
            print(self.stk[:self.ptr])
    

* cf) __len__(), __contains__() 함수

- __len__() : 클래스형의 인스턴스를 전달할 수 있다. obj? ? ? len(obj)

(클래스형의 인스턴스 : 새로 만든 객체 (?))

7.1. 클래스(class)와 인스턴스 - 왕초보를 위한 Python (wikidocs.net)

- __contains__() : x in obj

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

from typing import Any

class FixedStack:
    class Empty(Exception):
        pass
    class Full(Exception):
        pass
    def __init__(self, capacity: int = 256) -> None:
        self.stk = [None] * capacity
        self.capacity = capacity
        self.ptr = 0
    def __len__(self) -> int:
        return self.ptr
    def is_empty(self) -> bool:
        return self.ptr <= 0
    def is_full(self) -> bool:
        return self.ptr >= self.capacity
    def push(self, value: Any) -> None:
        if self.is_full():
            raise FixedStack.Full
        self.stk[self.ptr] = value
        self.ptr += 1
    def pop(self) -> Any:
        if self.is_empty():
            raise FixedStack.Empty
        self.ptr -= 1
        return self.stk[self.ptr]
    def peek(self) -> Any:
        if self.is_empty():
            raise FixedStack.Empty
        return self.stk[self.ptr -1]
    def clear(self) -> None:
        self.ptr = 0
    def find(self, value:Any) -> Any:
        for i in range(self.ptr -1, -1, -1):
            if self.stk[i] == value:
                return i
        return -1
    def count(self, value:Any) -> bool:
        c = 0
        for i in range(self.ptr):
            if self.stk[i] == value:
                c += 1
        return c
    def __contains__(self, value:Any) -> bool:
        return self.count(value)
    def dump(self)-> None:
        if self.is_empty():
            print('스택이 비어있습니다.')
        else:
            print(self.stk[:self.ptr])
    

스택 프로그램

from enum import Enum
from class_making import FixedStack

Menu = Enum('Menu', ['푸시', '팝', '피크', '검색', '덤프', '종료'])

def select_menu() -> Menu:
    s = [f'({m.value}{m.name}' for m in Menu]
    while True:
        print(*s, sep = '   ', end = '')
        n = int(input(': '))
        if 1 <= n <= len(Menu):
            return Menu(n)

s = FixedStack(64) #capacity 64

while True:
    print(f'현재 데이터 개수 : {len(s)} / {s.capacity}')
    menu = select_menu()

    if menu == Menu.푸시:
        x = int(input('데이터를 입력하세요: '))
        try:
            s.push(x)
        except FixedStack.Full:
            print('스택이 가득 차 있습니다.')
    elif menu == Menu.팝:
        try:
            x = s.pop()
            print(f'팝한 데이터는 {x}입니다.')
        except FixedStack.Empty:
            print('스택이 비어있습니다.')
    elif menu == Menu.피크:
        try:
            x = s.peek()
            print(f'피크한 데이터는 {x}입니다.')
        except FixedStack.Empty:
            print('스택이 비어있습니다.')
    elif menu == Menu.검색:
        x = int(input('검색할 값을 입력하세요 : '))
        if x in s:
            print(f'{s.count(x)}개 포함되고, 맨 앞의 위치는 {s.find(x)}입니다.')
        else:
            print('검색값을 찾을 수 없습니다.')
    elif menu == Menu.덤프:
        s.dump()
    else:
        break


    

 

'Computer Science > 자료구조' 카테고리의 다른 글

[5.15] 05 -1 재귀 알고리즘의 기본  (0) 2021.05.15
[5.12] 04-2 큐  (0) 2021.05.13
[5.10] * class 보충 학습  (0) 2021.05.10
[5.8] 03 검색 알고리즘 - 해시법  (0) 2021.05.08
[5.5-6] 03 검색 알고리즘  (0) 2021.05.05