반응형

큐(Queue)는 데이터를 넣고빼는 자료구조 중 하나로, 먼저 삽입된 데이터가 먼저 추출되는 FIFO(First In First Out) 구조를 가지고 있다. 큐는 Front, Rear라는 두개의 포인터를 사용하여 데이터를 관리한다.

 

Front : 다음 추출될 데이터를 가리킨다.

Rear : 다음 데이터가 저장될 공간을 가리킨다.

 

데이터를 삽입하는 행위를 enque, 추출하는 행위를 deque라고 부른다. enque 및 deque 실행 시 포인터 관리에 유의해야 한다.

(구현 방법에 따라 포인터의 증감 순서는 조금씩 다를 수 있다.)

 

 

1. 변수

  1) Capacity : 크기

  2) Front : 큐의 맨 앞

  3) Rear : 큐의 맨 뒤

  4) No : 큐에 들어있는 데이터의 갯수

 

2. 함수

  1) enque() : 큐에 데이터를 넣는 함수

  2) deque() : 큐에서 데이터를 빼는 함수

  3) __len__() : 큐에 넣어있는 데이터의 갯수를 반환하는 함수

  4) dump() : 큐 안에 있는 데이터를 순차적으로 모두 읽는 함수

  5) peek() : 맨 앞 데이터를 들여다보는 함수

  6) find() : 큐에서 특정 값을 찾아 인덱스를 반환하는 함수

  7) count() : 큐 안에서 특정 값의 갯수를 찾아 반환하는 함수

  8) contains() : 큐 안에 특정 값의 존재 여부를 찾아 반환하는 함수

  9) clear() : 큐를 초기화하는 함수

  10) is_full() : 큐가 가득 찼는지 확인하는 함수

  11) is_empty() : 큐가 비었는지 확인하는 함수

 

3. Exception

  1) Empty : 큐가 빈 경우 발생하는 Exception

  2) Full : 큐가 가득 찬 경우 발생하는 Exception

 

* 구현 내용

class FixedQueue:
    
    class Full(Exception):
        pass

    class Empty(Exception):
        pass

    def __init__(self, c : int):
        self.capacity = c
        self.front = 0
        self.rear = 0
        self.no = 0
        self.queue = [None] * self.capacity

    def is_full(self) -> bool:
        if self.no >= self.capacity:
            return True
        else:
            return False

    def is_empty(self) -> bool:
        if self.no <= 0:
            return True
        else:
            return False

    def enque(self, data):
        if self.is_full():
            raise FixedQueue.Full
        self.queue[self.rear] = data
        self.rear += 1
        self.no += 1
        if self.rear == self.capacity:
            self.rear = 0

    def deque(self):
        if self.is_empty():
            raise FixedQueue.Empty
        r_data = self.queue[self.front]
        self.front += 1
        self.no -= 1
        if self.front == self.capacity:
            self.front = 0
        return r_data
        
    def __len__(self):
        return self.no

    def dump(self):
        if self.is_empty():
            print('큐가 비었습니다.')
        else:
            for i in range(self.no):
                print(self.queue[(i + self.front)%self.capacity])

    def peek(self):
        if self.is_empty():
            raise FixedQueue.Empty
        return self.queue[self.front]

    def find(self, value):
        for i in range(self.no):
            idx = (i + self.front) % self.capacity
            if self.queue[idx] == value:
                return idx
        return -1

    def count(self, value):
        c = 0
        for i in range(self.no):
            idx = (i + self.front) % self.capacity
            if self.queue[idx] == value:
                c += 1
        return c

    def contains(self, value):
        return self.count(value)

    def clear(self):
        self.no = 0
        self.front = 0
        self.rear = 0

 

반응형

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

스택(Stack) 파이썬으로 구현하기  (0) 2020.12.20
반응형

스택(Stack)은 데이터를 넣고 뺄 수 있는 자료구조의 형태 중 하나이다. 

스택에 데이터를 넣고 빼는 방법은 총알을 탄창에 넣고 총을 쏘는 것과 똑같다.

 

아래의 맨 왼쪽과 같이 빈 탄창과 총알 4개가 있다고 하자. 총알 4개를 1번부터 순서대로 넣으면 가운데 그림처럼 될 것이다. 이후 총을 쏘기 시작하면 맨 마지막에 넣은 4번 총알부터 발사가 될 것이다. 

  (탄창 = Stack, 총알 = Data) 과 같이 생각하면 된다. 스택에 데이터를 넣는 과정은 탄창에 총알을 넣는 과정과 동일하며, 스택에서 데이터를 빼는 과정은 탄창에서 총알이 발사되는 과정과 동일하다.

 

스택에 데이터를 넣는 행위를 Push, 스택에서 데이터를 빼는 행위는 Pull이라고 부른다. 4개의 데이터를 스택에 넣고 빼는 과정을 생각해보면, 가장 먼저 넣은 데이터(1번)이 가장 마지막에 나오는 것을 알 수 있다. 이런 데이터 구조를 FIFO(First In Last Out, = 선입후출)이라고 부른다. 

 

스택은 크기 제한(Top = capacity)을 가지고 있으며, 데이터는 맨 아래(Bottom)부터 꼭대기까지 하나씩 순차적으로 들어간다. 데이터를 꺼낼 때는 맨 위에서부터(가장 최근에 넣은 것부터) 하나씩 뺄 수 있다. 이제 해당 자료구조를 파이썬으로 구현하기 위한 함수, 변수들을 생각해보자.

 

* 변수

1. 스택 포인터(ptr)

 : 현재 스택에 데이터가 어디까지 쌓여있는지 나타내는 포인터. 

2. 크기(capacity)

 : 스택의 크기를 나타내는 변수. 스택 생성 시 지정해준다.

 

* 함수

1. __init__() : 변수 초기화

2. push() : 스택에 데이터를 한개 삽입한다.

3. pop() : 스택에서 데이터를 한개 꺼낸다.

4. __len__() : 현재 쌓여있는 데이터의 크기를 반환한다.

5. is_empty() : 스택의 empty 여부를 확인한다.

6. is_full() : 스택이 가득 찼는지 확인한다.

7. peek() : 가장 최근에 쌓인 데이터를 읽는다.

8. clear() : 스택을 초기화한다.

9. find() : 스택 내에서 특정 값을 찾는다.

10. count() : stack에 있는 특정 값의 개수를 찾는다.

11. contains() : 특정 값을 포함하고 있는지 확인한다.

12. dump() : 스택 내의 모든 데이터를 출력한다.

 

구현은 아래와 같다. 스택 포인터(ptr)이 작동하는 방식을 잘 봐야 한다.

1. 스택 포인터는 항상 빈 공간을 가리키고 있다.

2. 포인터의 위치만을 수정하여 스택초기화, 데이터 제거가 가능하다.

 

#Fixed스택 직접 구현해보기
from typing import Any

class FixedStack:
    ##Stack Pointer는 미리 다음 빈 공간을 가리키고 있다.

    class Empty(Exception):
        pass
    class Full(Exception):
        pass

    def __init__(self , c : int) -> None:
        ## 변수 초기화 함수.
        ## stack의 크기를 생성 시 전달받는다.
        self.ptr = 0
        self.capacity = c
        self.stk = [None] * c

    def __len__(self) -> int:
        ## Stack의 길이를 반환하는 함수
        ## ptr은 다음 빈 공간을 가리키고 있기 때문에 길이와 같다.
        return self.ptr

    def is_empty(self) -> bool:
        ## Stack이 비었는지 확인하는 함수
        return self.ptr <= 0

    def is_full(self) -> bool:
        ## Stack이 가득 찼는지 확인하는 함수
        return self.ptr >= self.capacity

    def push(self, data: int) -> None:
        if self.is_full():
            raise FixedStack.Full
        self.stk[self.ptr] = data
        self.ptr += 1
    
    def pop(self) -> any:
        ## Stack의 가장 바깥에 쌓여있는 데이터를 Stack에서 빼는 함수.
        ## 비었는지 확인하고 data를 return한다. 이 때 ptr만 하나 줄여주면 된다.
        if self.is_empty():
            raise FixedStack.Empty
        self.ptr -= 1
        return self.stk[self.ptr]

    def peek(self):
        ## 가장 바깥에 쌓여있는 데이터를 읽어오는 함수
        ## 비어있는지 확인 후 data를 return한다.
        if self.is_empty():
            raise FixedStack.Empty
        return self.stk[self.ptr-1]

    def clear(self):
        ## Stack을 초기화하는 함수
        self.ptr = 0
    
    def find(self, value: Any) -> Any:
        ## 전달받은 값을 찾는 함수.
        ## 찾으면 index를 반환한다.
        for i in range(self.ptr - 1, -1, -1):
            if self.stk[i] == value:
                return i
        return -1

    def count(self, value : Any) -> int:
        ## Stack 안에 찾고자 하는 값이 몇개인지 찾는다.
        count = 0
        for i in range(self.ptr):
            if self.stk[i] == value:
                count += 1
        return count

    def __contains__(self, value: Any) -> bool:
        ## Stack이 특정 값을 포함하고 있는지 확인하는 함수
        return self.count(value)

    def dump(self) -> None:
        ## 데이터를 바닥부터 꼭대기까지 출력한다.
        ## ptr까지 출력해야 하는 이유는 그 뒤에 삭제하지 않고 남은 데이터가 있을 수도 있기 때문!
        if self.is_empty():
            raise FixedStack.Empty
        else:
            print(self.stk[:self.ptr])
        

 

 

 

반응형

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

큐(Queue) 파이썬으로 구현하기  (0) 2020.12.21

+ Recent posts