카테고리 없음

[5.13] 링 버퍼로 큐 구현하기

토마토. 2021. 5. 14. 11:31

링 버퍼로 큐 구현하기

링 버퍼 ring buffer : 배열 맨 끝의 원소 뒤에 맨 앞의 원소가 연결되는 자료 구조

-> FIFO에서 First Out을 하는 경우, 나머지 모든 원소의 인덱스를 변경해야 하는 문제(O(n)) 해결

 

from typing import Any

class FixedQueue:

    class Empty(Exception):
        pass
    class Full(Exception):
        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 <= 0
    
    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:
        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:
        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:
        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:
        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()
    

양방향 대기열 덱의 구조 -> collections.deque 컨테이너(파이썬)

덱 deque - double-ended queue - 앞/끝 양쪽에서 데이터를 삽입/삭제할 수 있는 자료구조. 

 

링 버퍼로 큐 프로그램 만들기

- 스택과 기본적인 구조가 같다. 

from enum import Enum
from class_making 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) #capacity 64

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

    if menu == Menu.인큐:
        x = int(input('데이터를 입력하세요: '))
        try:
            q.enque()
        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

cf) 링 버퍼의 활용

- 오래된 데이터를 버리는 용도로 활용하기

n = int(input('정수를 몇 개 저장할까요? : '))
a = [None] * n

cnt = 0
while True:
    a[cnt % n] = int(input((f'{cnt+1}번째 정수를 입력하세요 : ')))
    cnt += 1

    retry = input(f'계속 할까요? ( Y ... Yes / N ... No) : ')
    if retry in {'N', 'n'}:
        break

i = cnt - n
if i < 0: i = 0

while i < cnt:
    print(f'{i + 1}번째 = {a[i % n]}')
    i += 1