push : 스택에 데이터를 넣음
pop : 스택에서 데이터를 꺼냄
top : 푸시 팝이 이루어지는(나중에 들어간 데이터, 먼저 나올 데이터가 있는) 윗부분
bottom : 먼저 들어간 데이터가 쌓이는 아랫부분
⇒ 넣은(push) 데이터는 스택 꼭대기(top)에 쌓이고, 꺼낼 때도(pop) 꼭대기(top)에서 데이터가 나옴, 방금 넣은걸 꺼내는거
스택 구현하기 - 고정길이스택.. 실제로는 가변리스트로 쓰는거같음
용어만 정리하자면
스택 크기(capacity)
: 스택의 최대 크기를 나타내는 int형 정수, 스택으로 쓸 배열의 길이 // = len(stk)
스택 포인터(ptr)
: 스택에 쌓여 있는 데이터의 개수를 나타내는 정숫값
: 비어있으면 0, 가득차있으면 capacity와 같음
: 마지막에 푸시한 데이터는 stk[ptr-1]에 있음
: 데이터를 푸시할때 ptr을 1씩 증가시키고, 팝할때 ptr을 1씩 감소시킴
고정 길이 스택 구현 - FixedStack 클래스
# 고정 길이 스택 클래스 FixedStack 구현하기
# Do it! 실습 4-1 [A]
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
# Do it! 실습 4-1 [B]
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
# Do it! 실습 4-1 [C]
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])
스택 프로그램
# [Do it! 실습 4-2] 고정 길이 스택 FixedStack의 사용하기
from enum import Enum
from fixed_stack 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) # 최대 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
스택처럼 데이터를 임시저장할 때 사용하는 자료구조
데이터의 입출력은 선입선출(FIFO)
먼저 들어간 게 먼저 나옴
enqueue : 큐에 데이터를 추가
dequeue : 큐에서 데이터를 꺼냄
front : 데이터를 꺼내는 쪽
rear : 데이터를 넣는 쪽;
배열로 큐 구현하기
링 버퍼로 큐 구현하기
고정 길이 큐 클래스 - FixedQueue
# 고정 길이 큐 클래스 FixedQueue 구현하기
# Do it! 실습 4-3 [A]
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
# Do it! 실습 4-3 [B]
def enque(self, x: Any) -> None:
"""데이터 x를 인큐"""
if self.is_full():
raise FixedQueue.Full # 큐가 가득 찬 경우 예외처리를 발생
self.que[self.rear] = x # rear인덱스에 값을 저장
self.rear += 1 # rear값을 1 증가
self.no += 1 # 개수도 1 증가
if self.rear == self.capacity: # rear가 크기랑 같아지면
self.rear = 0 # 0으로 만들어줌, 인덱스는 n-1까지니까.
# Do it! 실습 4-3 [C]
def deque(self) -> Any:
"""데이터를 디큐합니다"""
if self.is_empty():
raise FixedQueue.Empty # 큐가 비어 있는 경우 예외처리를 발생
x = self.que[self.front] # front인덱스의 값을 꺼내줌
self.front += 1 # front값을 1 증가
self.no -= 1 # 개수는 1감소
if self.front == self.capacity: # front도 크기랑 같아지면
self.front = 0 # 0으로 만들어줌
return x # 꺼낸 값 저장한 변수 반환
# Do it! 실습 4-3 [D]
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문 개수만큼 돌면 front 더해준 인덱스부턴데
# i+front에 크기로 나눠서 나머지 구해주면 인덱스 맞춰서 돌아줌
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()
링 버퍼로 큐 프로그램 만들기
# [Do it! 실습 4-4] 고정 길이 큐 클래스(FixedQueue)를 사용하기
from enum import Enum
from fixed_queue import FixedQueue
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)
q = FixedQueue(64) # 최대 64개를 인큐할 수 있는 큐 생성(고정 길이)
while True:
print(f'현재 데이터 개수: {len(q)} / {q.capacity}')
menu = select_menu() # 메뉴 선택
if menu == Menu.인큐: # 인큐
x = int(input('인큐할 데이터를 입력하세요.: '))
try:
q.enque(x)
except FixedQueue.Full:
print('큐가 가득 찼습니다.')
elif menu == Menu.디큐: # 디큐
try:
x = q.deque()
print(f'디큐한 데이터는 {x}입니다.')
except FixedQueue.Empty:
print('큐가 비어 있습니다.')
elif menu == Menu.피크: # 피크
try:
x = q.peek()
print(f'피크한 데이터는 {x}입니다.')
except FixedQueue.Empty:
print('큐가 비었습니다.')
elif menu == Menu.검색: # 검색
x = int(input('검색할 값을 입력하세요.: '))
if x in q:
print(f'{q.count(x)}개 포함되고, 맨 앞의 위치는 {q.find(x)}입니다.')
else:
print('검색값을 찾을 수 없습니다.')
elif menu == Menu.덤프: # 덤프
q.dump()
else:
break
참고 ::