후입 선출 방식의 데이터 구조 (Last In First Out)
Bottom : 가장 밑에 있는 데이터 또는 그 데이터의 인덱스
Top : 가장 위에 있는 데이터 또는 그 데이터의 인덱스
Capacity : 데이터를 담기 위한 용적
size : 데이터의 개수
그리고 데이터를 추가하는 작업을 push
또한 데이터를 삭제하는 작업을 pop
비어있는 스택에서 원소를 추출하려고 할 때 stack underflow
꽉 차있는 스택에서 원소를 삽입하려고 할 때 stack overflow
from typing import Any
class FixedStack:
"""고정 길이 스택 클래스"""
class Empty(Exception):
"""비어 있는 FixedStack에 pop 또는 peek를 호출할 때 내보내는 예외 처리"""
pass
class Full(Exception):
"""가득 찬 FixedStack에 push를 호출할 때 내보내는 예외 처리"""
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:
"""스택에 value를 푸시"""
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:
"""스택에서 value를 찾아 첨자(없으면 -1)를 반환"""
for i in range(self.ptr - 1, -1, -1): # 꼭대기 쪽부터 선형 검색
if self.stk[i] == value:
return i # 검색 성공
return -1 # 검색 실패
def count(self, value: Any) -> bool:
"""스택에 포함되어있는 value의 개수를 반환"""
c = 0
for i in range(self.ptr): # 바닥 쪽부터 선형 검색
if self.stk[i] == value:
c += 1 # 들어 있음
return c
def __contains__(self, value: Any) -> bool:
"""스택에 value가 있는가?"""
return self.count(value)
def dump(self) -> None:
"""덤프(스택 안의 모든 데이터를 바닥부터 꼭대기 순으로 출력)"""
if self.is_empty(): # 스택이 비어 있음
print('스택이 비어 있습니다.')
else:
print(self.stk[:self.ptr])
Deque란 double-ended-queue의 줄임말로 앞과 뒤에서 즉, 양방향에서 데이터를 처리할 수 있는 queue형 자료구조
from typing import Any
from collections import deque
class Stack:
"""고정 길이 스택 클래스(collections.deque를 사용)"""
def __init__(self, maxlen: int = 256) -> None:
"""초기화 선언"""
self.capacity = maxlen
self.__stk = deque([], maxlen)
def __len__(self) -> int:
"""스택에 쌓여있는 데이터 개수를 반환"""
return len(self.__stk)
def is_empty(self) -> bool:
"""스택이 비어 있는지 판단"""
return not self.__stk
def is_full(self) -> bool:
"""스택이 가득 찼는지 판단"""
return len(self.__stk) == self.__stk.maxlen
def push(self, value: Any) -> None:
"""스택에 value를 푸시"""
self.__stk.append(value)
def pop(self) -> Any:
"""스택에서 데이터를 팝"""
return self.__stk.pop()
def peek(self) -> Any:
"""스택에서 데이터를 피크"""
return self.__stk[-1]
def clear(self) -> None:
"""스택을 비웁니다"""
self.__stk.clear()
def find(self, value: Any) -> Any:
"""스택에서 value를 찾아 인덱스(없으면 -1)를 반환"""
try:
return self.__stk.index(value)
except ValueError:
return -1
def count(self, value: Any) -> int:
"""스택에 포함된 value의 개수를 반환"""
return self.__stk.count(value)
def __contains__(self, value: Any) -> bool:
"""스택에 value가 포함되어 있는지 판단"""
return self.count(value)
def dump(self) -> int:
"""스택 안에 있는 모든 데이터를 나열"""
print(list(self.__stk))
선입 선출 방식의 데이터 구조 (First In First Out)
정해진 한 곳(top)을 통해서 삽입, 삭제가 이루어지는 스택과는 달리
큐는 한쪽 끝에서 삽입 작업이, 다른 쪽 끝에서 삭제 작업이 양쪽으로 발생
이때 삭제연산만 수행되는 곳을 프론트(front)
삽입연산만 이루어지는 곳을 리어(rear)로 정하여
큐의 리어에서 이루어지는 삽입연산을 인큐(enQueue)
프론트에서 이루어지는 삭제연산을 디큐(dnQueue) 로 정의함
# 고정 길이 큐 클래스 FixedQueue 구현하기
from typing import Any
class FixedQueue:
class Empty(Exception):
"""비어 있는 FixedQueue에 대해 deque 또는 peek를 호출할 때 내보내는 예외처리"""
pass
class Full(Exception):
"""가득 찬 FixedQueue에 enque를 호출할 때 내보내는 예외처리"""
pass
def __init__(self, capacity: int) -> None:
"""초기화 선언"""
self.no = 0 # 현재 데이터 개수
self.front = 0 # 맨앞 원소 커서
self.rear = 0 # 맨끝 원소 커서
self.capacity = capacity # 큐의 크기
self.que = [None] * capacity # 큐의 본체
def __len__(self) -> int:
"""큐에 있는 모든 데이터 개수를 반환"""
return self.no
def is_empty(self) -> bool:
"""큐가 비어 있는지 판단"""
return self.no <= 0
def is_full(self) -> bool:
"""큐가 가득 찼는지 판단"""
return self.no >= self.capacity
def enque(self, x: Any) -> None:
"""데이터 x를 인큐"""
if self.is_full():
raise FixedQueue.Full # 큐가 가득 찬 경우 예외처리를 발생
self.que[self.rear] = x
self.rear += 1
self.no += 1
if self.rear == self.capacity:
self.rear = 0
def deque(self) -> Any:
"""데이터를 디큐합니다"""
if self.is_empty():
raise FixedQueue.Empty # 큐가 비어 있는 경우 예외처리를 발생
x = self.que[self.front]
self.front += 1
self.no -= 1
if self.front == self.capacity:
self.front = 0
return x
def peek(self) -> Any:
"""데이터를 피크합니다(맨 앞 데이터를 들여다 봄)"""
if self.is_empty():
raise FixedQueue.Empty # 큐가 비어 있으면 예외처리를 발생
return self.que[self.front]
def find(self, value: Any) -> Any:
"""큐에서 value를 찾아 인덱스를 반환하고 없으면 -1을 반환합니다"""
for i in range(self.no):
idx = (i + self.front) % self.capacity
if self.que[idx] == value: # 검색 성공
return idx
return -1 # 검색 실패
def count(self, value: Any) -> bool:
"""큐에 포함되어 있는 value의 개수를 반환합니다"""
c = 0
for i in range(self.no): # 큐 데이터를 선형 검색
idx = (i + self.front) % self.capacity
if self.que[idx] == value: # 검색 성공
c += 1 # 들어있음
return c
def __contains__(self, value: Any) -> bool:
"""큐에 value가 포함되어 있는지 판단합니다"""
return self.count(value)
def clear(self) -> None:
"""큐의 모든 데이터를 비웁니다"""
self.no = self.front = self.rear = 0
def dump(self) -> None:
"""모든 데이터를 맨 앞에서 맨 끝 순서로 출력합니다"""
if self.is_empty(): # 큐가 비어 있으면 예외처리를 발생
print('큐가 비어 있습니다.')
else:
for i in range(self.no):
print(self.que[(i + self.front) % self.capacity], end=' ')
print()