[자료ꡬ쑰] 큐(Queue)

2022. 3. 10. 16:12

Questions


  • Stackκ³Ό Queue의 차이점은 λ¬΄μ—‡μΈκ°€μš”? (N사 μ „ν™”λ©΄μ ‘)
  • Priority Queue의 λ™μž‘ 원리가 μ–΄λ–»κ²Œ λ˜λ‚˜μš”? (N사 μ „ν™”λ©΄μ ‘)
  • 큐 / μš°μ„ μˆœμœ„ 큐의 κ°œλ…μ— λŒ€ν•΄ μ„€λͺ…ν•΄λ³΄μ„Έμš”.
  • 큐 μ‚½μž…(enqueue) / μ‚­μ œ(dequeue) ν•¨μˆ˜λ₯Ό λ°°μ—΄ / λ§ν¬λ“œλ¦¬μŠ€νŠΈλ‘œ κ΅¬ν˜„ν•˜λΌ.
  • μŠ€νƒ 2개둜 큐 1개λ₯Ό κ΅¬ν˜„ν•œ MyQueue 클래슀λ₯Ό κ΅¬ν˜„ν•˜λΌ.

 

큐(Queue)의 κ°œλ…


νλŠ” λ°°μ—΄κ³Ό ν•¨κ»˜ κ°€μž₯ μ‰¬μš΄ 자료 ꡬ쑰 쀑 ν•˜λ‚˜μ΄λ‹€. νλŠ” μ»΄ν“¨ν„°μ—μ„œ κ°€μž₯ 핡심적인 μ†Œν”„νŠΈμ›¨μ–΄ 쀑 ν•˜λ‚˜μΈ μš΄μ˜μ²΄μ œμ—μ„œλ„ 많이 쓰인닀. 또, μΈν„°λ„·μ—μ„œ λ„€νŠΈμ›Œν¬ κΈ°λŠ₯μ—μ„œλ„ 많이 μ‚¬μš©λœλ‹€.

 

Queue의 사전적 μ˜λ―ΈλŠ” 1. (무엇을 κΈ°λ‹€λ¦¬λŠ” μ‚¬λžŒ, μžλ™μ°¨ λ“±μ˜) μ€„, ν˜Ήμ€ μ€„을 μ„œμ„œ κΈ°λ‹€λ¦¬λŠ” 것을 μ˜λ―Έν•œλ‹€. 즉, κ°€μž₯ λ¨Όμ € 넣은 데이터λ₯Ό κ°€μž₯ λ¨Όμ € κΊΌλ‚Ό 수 μžˆλŠ” μ„ μž…μ„ μΆœ = FIFO (First-In, First-Out) λ°©μ‹μ˜ 자료ꡬ쑰λ₯Ό λ§ν•œλ‹€.

큐의 μ‚½μž… 연산은 ν•œ μͺ½ 끝(rear)μ—μ„œ, μ‚­μ œ 연산은 λ°˜λŒ€μͺ½(front)μ—μ„œ μΌμ–΄λ‚œλ‹€. μ΄λ•Œ, 큐의 λ¦¬μ–΄μ—μ„œ μ΄λ£¨μ–΄μ§€λŠ” μ‚½μž…μ—°μ‚°μ„ μΈν(enQueue), ν”„λ‘ νŠΈμ—μ„œ μ΄λ£¨μ–΄μ§€λŠ” μ‚­μ œμ—°μ‚°μ„ λ””큐(dnQueue)라고 λΆ€λ₯Έλ‹€. ⇒ 접근방법은 κ°€μž₯ μ²« μ›μ†Œμ™€ λ μ›μ†Œλ‘œλ§Œ κ°€λŠ₯

큐에 μš”μ†Œκ°€ ν•˜λ‚˜λ„ λ“€μ–΄μžˆμ§€ μ•Šμ„ λ•ŒλŠ” κ³΅λ°±(empty) μƒνƒœλΌ ν•˜κ³  꽉 μ°¨μ„œ 더 이상 μš”μ†Œλ₯Ό μ§‘μ–΄λ„£μ§€ λͺ»ν•˜ 경우 ν¬ν™”(full) μƒνƒœλΌκ³  ν•œλ‹€.

 

큐의 ν™œμš© μ˜ˆμ‹œ


νλŠ” 주둜 데이터가 μž…λ ₯된 μ‹œκ°„ μˆœμ„œλŒ€λ‘œ μ²˜λ¦¬ν•΄μ•Ό ν•  ν•„μš”κ°€ μžˆλŠ” 상황에 μ΄μš©ν•œλ‹€.

  • μš°μ„ μˆœμœ„κ°€ 같은 μž‘μ—… μ˜ˆμ•½ (ν”„λ¦°ν„°μ˜ μΈμ‡„ λŒ€κΈ°μ—΄)
  • ν”„λ‘œμ„ΈμŠ€ 관리
  • λ„ˆλΉ„ μš°μ„  탐색(BFS, Breadth-First Search) κ΅¬ν˜„
  • μΊμ‹œ(Cache) κ΅¬ν˜„

 

큐의 κ΅¬ν˜„


Python으둜 큐λ₯Ό κ΅¬ν˜„ν•˜λŠ” 방법은 μ„Έ κ°€μ§€ 정도가 있으며 각 λ°©λ²•λ§ˆλ‹€ μž₯단점이 μžˆλ‹€.

  1. List μžλ£Œν˜• μ‚¬μš©
  2. Collections λͺ¨λ“ˆμ˜ deque μ‚¬μš©
  3. queue λͺ¨λ“ˆμ˜ Queue 클래슀 μ‚¬μš©

 

1. List μžλ£Œν˜• μ‚¬μš©

  • κ΅¬ν˜„
      # 큐의 맨 끝에 데이터 μ‚½μž…
      queue = [1, 2, 3]
      queue.append(4)
      queue.append(5)
        
      print(queue)
        
      #-----------------------------------
        
      # 큐 맨 μ•ž 데이터 μ‚­μ œ
      queue.pop(0)     # 1 μ‚­μ œ
      queue.pop(0)     # 2 μ‚­μ œ
        
      print(queue)
    
  • 파이썬의 κΈ°λ³Έ μžλ£Œν˜•μΈ listλ₯Ό μ‚¬μš©ν•œ 방법이닀. .append(x) λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ°°μ—΄μ˜ 끝에 데이터λ₯Ό μΆ”κ°€ν•˜κ³ , .pop(0) λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ 첫 데이터λ₯Ό μ œκ±°ν•œλ‹€. μŠ€νƒμ„ κ΅¬ν˜„ν•  λ•Œμ™€ λ°˜λŒ€λ‘œ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ 큐 자료ꡬ쑰λ₯Ό μ‚¬μš©ν•˜λŠ” νš¨κ³Όκ°€ λ‚œλ‹€. insert(0, x) ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 맨 μ•žμ— 데이터λ₯Ό λ„£μ–΄ λ°˜λŒ€ λ°©ν–₯으둜 μ‚½μž…λ„ κ°€λŠ₯ν•˜λ‹€.
  • 단점 : μ„±λŠ₯ 문제
  • 단, 이 방법은 μ„±λŠ₯적으둜 λ¬Έμ œκ°€ μžˆλ‹€. list μžλ£Œν˜•μ€ λ¬΄μž‘μœ„ 접근에 μ΅œμ ν™”λœ 자료 ꡬ쑰이기 λ•Œλ¬Έμ΄λ‹€. pop(0)μ΄λ‚˜ insert(0, x)λŠ” O(n)의 μ‹œκ°„ λ³΅μž‘λ„λ₯Ό κ°€μ§€κ³  μžˆμ–΄ λ‹΄λŠ” 데이터 κ°œμˆ˜κ°€ λ§Žμ•„μ§ˆμˆ˜λ‘ ν™•μ—°νžˆ λŠλ €μ§€κ²Œ λ˜λŠ”λ°, μ΄λŠ” 첫번째 데이터λ₯Ό μ œκ±°ν•˜λ©΄ κ·Έ 뒀에 λͺ¨λ“  데이터λ₯Ό μ•žμœΌλ‘œ ν•œ μΉΈμ”© λ‹ΉκΈ°κ³  맨 μ•žμ— 데이터λ₯Ό μ‚½μž…ν•˜λ €λ©΄ λͺ¨λ“  데이터λ₯Ό ν•œ μΉΈμ”© λ―ΈλŠ” 연산이 λ‚΄λΆ€μ μœΌλ‘œ ν¬ν•¨λ˜μ–΄ 있기 λ•Œλ¬Έμ΄λ‹€.

 

2. Collections λͺ¨λ“ˆμ˜ deque μ‚¬μš©

πŸ’‘ 데크(=디큐, deque)λŠ” dobule-ended queue의 μ•½μžλ‘œ 데이터λ₯Ό μ–‘λ°©ν–₯μ—μ„œ μΆ”κ°€ν•˜κ³  μ œκ±°ν•  수 μžˆλŠ” μžλ£Œκ΅¬μ‘°λ‹€. μŠ€νƒκ³Ό 큐의 각 νŠΉμ§•μ΄ λšœλ ·ν•˜μ§€λ§Œ λ³„λ„λ‘œ ꡬ뢄해 μ‚¬μš©ν•˜κΈ° 번거둜운데, dequeλŠ” 두 μžλ£Œν˜•μ˜ νŠΉμ§•μ„ λͺ¨λ‘ κ°–λŠ”λ‹€. Double Ended Queueλ₯Ό μ§μ—­ν•˜λ©΄ ‘μ–‘ 끝이 μ•žμ΄ λ˜λŠ” 큐’μ΄μ§€λ§Œ, λ°ν¬λŠ” 큐의 μ„±μ§ˆλ§Œ κ°–λŠ” 것이 μ•„λ‹ˆλΌ μŠ€νƒκ³Ό 큐의 μ„±μ§ˆμ„ λͺ¨λ‘ κ°–λŠ”λ‹€. 즉, μ–‘μͺ½ λμ—μ„œ μ‚½μž…κ³Ό μ‚­μ œκ°€ λͺ¨λ‘ κ°€λŠ₯ν•œ μžλ£Œκ΅¬μ‘°λ‹€.파이썬의 collections λͺ¨λ“ˆμ—μ„œ dequeλ₯Ό λΆˆλŸ¬μ™€ μ‚¬μš©ν•œλ‹€. 파이썬의 λ¦¬μŠ€νŠΈμ™€ μœ μ‚¬ν•˜μ§€λ§Œ Collections.deque의 연산인 appendleft()와 popleft() 의 μ‹œκ°„λ³΅μž‘λ„λ₯Ό μ‚΄νŽ΄λ³΄λ©΄ μ•žλ’€μ—μ„œ 데이터λ₯Ό μ²˜λ¦¬ν•˜λŠ” 속도가 λͺ¨λ‘ O(1)둜 맀우 λΉ λ₯Έ 것을 μ•Œ 수 μžˆλ‹€. μ΄λŠ” λ‚΄λΆ€μ μœΌλ‘œ doubly linked list둜 κ΅¬ν˜„λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ΄λ‹€. λ”°λΌμ„œ μ•žμ„œ 리슀트둜 κ΅¬ν˜„ν•œ 큐 ꡬ쑰보닀 μ„±λŠ₯이 λ›°μ–΄λ‚˜λ‹€.
  • κ΅¬ν˜„
  from collections import deque
    
  # deque μ„ μ–Έ-----------------------------
  dq = deque([])
    
  # deque에 데이터 μΆ”κ°€
  dq.append(1)
  dq.append(2)
  dq.append(3)
  dq.append(4)
    
  print(dq)
    
  # deque의 맨 μ•ž μ›μ†Œ 제거------------------
  print(dq.popleft())   # 1 좜λ ₯ 및 제거
  print(dq.popleft())   # 2 좜λ ₯ 및 제거
  dq.popleft()          # 3 제거
  (dq.popleft))         # 4 제거
    
  print(dq)

 

  • 단점
  • λ¬΄μž‘μœ„ μ ‘κ·Όμ˜ μ‹œκ°„λ³΅μž‘λ„κ°€ O(n)이고, λ‚΄λΆ€μ μœΌλ‘œ linked listλ₯Ό μ‚¬μš©ν•΄ N번째 데이터에 μ ‘κ·Όν•˜λ €λ©΄ N번 μˆœνšŒκ°€ ν•„μš”ν•˜λ‹€.

 

3. Queueλͺ¨λ“ˆμ˜ queue λ©”μ†Œλ“œ ν™œμš©

  • κ΅¬ν˜„ 
    *  μ°Έκ³  : 기타 queue λͺ¨λ“ˆμ— μ •μ˜λœ 클래슀 μ •λ³΄λŠ” λ‹€μŒκ³Ό κ°™λ‹€.
    
    ν΄λž˜μŠ€λ‚΄μš©
    queue.Queue(maxSize) μ„ μž…μ„ μΆœ => 큐
    queue.LifoQueue(maxsize) ν›„μž…μ„ μΆœ 방식 큐 => μŠ€νƒ
    queue.PriorityQueue(maxsize) λ°μ΄ν„°λ§ˆλ‹€ μš°μ„ μˆœμœ„λ₯Ό μ£Όκ³  μš°μ„ μˆœμœ„κ°€ 높은 순으둜 데이터λ₯Ό 좜λ ₯ν•˜λŠ” μš°μ„ μˆœμœ„ 큐 (μš°μ„ μˆœμœ„ μˆ«μžκ°€ μž‘μ„ 수둝 높은 μˆœμœ„)
    queue.SimpleQueue μž…λ ₯μ œν•œμ΄ μ—†λŠ” μ„ μž…μ„ μΆœ 큐
    • 각 ν΄λž˜μŠ€λŠ” λ‹€μŒ λ©”μ†Œλ“œλ₯Ό λ™μΌν•˜κ²Œ μ‚¬μš©ν•œλ‹€.
    • qsize() : 큐 객체에 λ“±λ‘λœ μ•„μ΄ν…œ 갯수 λ°˜ν™˜
    • put(n) : 큐 객체에 μ•„μ΄ν…œ 등둝
    • put_nowait : λΈ”λ‘œν‚Ή 없이 큐 객체에 μ•„μ΄ν…œ 등둝
    • get : μ•„μ΄ν…œ 1개 λ°˜ν™˜
    • get_nowait() : λΈ”λ‘œν‚Ήμ—†μ΄ 큐 객체에 λ“€μ–΄μžˆλŠ” μ•„μ΄ν…œ λ°˜ν™˜
  •   from queue import queue
        
      # Queue μ„ μ–Έ
      que = Queue()
         
      # q에 데이터 μΆ”κ°€
      que.put(1)
      que.put(2)
      que.put(3)
      que.put(4)
         
      # queμ—μ„œ 맨 μ•ž μ›μ†Œ 제거
      print(que.get()) # 1
      print(que.get()) # 2
      print(que.get()) # 3
      print(que.get()) # 4
    
  • 파이썬의 Queue λͺ¨λ“ˆμ—μ„œλŠ” ν(Queue), μš°μ„ μˆœμœ„큐(PriorityQueue), μŠ€νƒ(LifoQueue)λ₯Ό μ œκ³΅ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 특히 큐 λͺ¨λ“ˆμ€ μŠ€λ ˆλ“œ ν™˜κ²½μ„ κ³ λ €ν•˜μ—¬ μž‘μ„±λ˜μ–΄ 있기 λ•Œλ¬Έμ— μ—¬λŸ¬ μŠ€λ ˆλ“œλ“€μ΄ λ™μ‹œμ— 큐(Queue), μš°μ„ μˆœμœ„ν(PriorityQueue), μŠ€νƒ(LifoQueue)κ³Ό 같은 객체에 μ ‘κ·Όν•˜μ—¬ μž‘μ—…μ„ μˆ˜ν–‰ν•˜μ—¬λ„ μ •μƒμ μœΌλ‘œ λ™μž‘ν•˜λŠ” 것을 보μž₯ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„  기본적인 Queueλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‰½κ²Œ Queueλ₯Ό ν™œμš©ν•΄ 보도둝 ν•˜κ² μŠ΅λ‹ˆλ‹€.



큐의 μ’…λ₯˜


μ„ ν˜• 큐 (Linear Queue)

μ„ ν˜• 큐(Linear Queue)λŠ” κ°€μž₯ 기본적인 ν˜•νƒœμ˜ 큐(Queue)이닀. μ„ ν˜• νμ—λŠ” 단점이 μ‘΄μž¬ν•˜λŠ”λ°, μ‚½μž… 및 μ‚­μ œλ₯Ό λ°˜λ³΅ν•˜λ‹€λ³΄λ©΄ rearκ°€ 맨 λ§ˆμ§€λ§‰ 인덱슀λ₯Ό 가리킀고, μ•žμ—λŠ” λΉ„μ–΄μžˆμ„ μˆ˜λ„ μžˆμ§€λ§Œ 이λ₯Ό 꽉 μ°Όλ‹€κ³  μΈμ‹ν•œλ‹€λŠ” 점이닀.

 μ΄λŠ” μ‹€μ œ λ°μ΄ν„°λŠ” μ‚­μ œ λ•Œλ§ˆλ‹€ ν•œ μΉΈ μ•žμœΌλ‘œ μ΄λ™μ‹œν‚€μ§€ μ•Šμ•˜κ³ , 인덱슀 λ‹¨μœ„λ‘œ 큐의 연산을 μ§„ν–‰ν–ˆκΈ° λ•Œλ¬Έμ΄λ‹€. 이에 μƒκ²¨λ‚œ 아이디어가 μ›ν˜• 큐이닀.

 

μ›ν˜• 큐 (=ν™˜ν˜• 큐, Circular Queue)

μ›ν˜• νλŠ” μ„ ν˜• 큐와 λ§ˆμ°¬κ°€μ§€λ‘œ 1차원 λ°°μ—΄λ‘œ κ΅¬ν˜„ν•˜μ§€λ§Œ, λ…Όλ¦¬μ μœΌλ‘œ λ°°μ—΄μ˜ 처음과 끝이 μ—°κ²°λ˜μ–΄ μžˆλŠ” κ²ƒμœΌλ‘œ μƒκ°ν•˜λŠ” 것이닀.

μ›ν˜• νμ—μ„œλŠ” front와 rear 의 κ°œλ…μ΄ μ•½κ°„ λ³€κ²½λœλ‹€. λ¨Όμ € 초기 값은 -1이 μ•„λ‹Œ 0이닀.

frontλŠ” 항상 큐의 첫 번째 μš”μ†Œμ˜ ν•˜λ‚˜ μ•žμ„, rearλŠ” λ§ˆμ§€λ§‰ μš”μ†Œλ₯Ό 가리킨닀.

  • μ²˜μŒμ— front, rearλŠ” λͺ¨λ‘ 0이고 μ‚½μž… μ‹œμ—λŠ” rearκ°€ λ¨Όμ € μ¦κ°€λ˜κ³ , μ¦κ°€λœ μœ„μΉ˜μ— μƒˆλ‘œμš΄ 데이터가 μ‚½μž…λœλ‹€.
  • 또 μ‚­μ œ μ‹œμ—λ„ frontκ°€ λ¨Όμ € μ¦κ°€λœ λ‹€μŒ, μ¦κ°€λœ μœ„μΉ˜μ—μ„œ 데이터λ₯Ό μ‚­μ œν•œλ‹€.

μ›ν˜• 큐 κ΅¬ν˜„

class CircularQueue:

#큐 μ΄ˆκΈ°ν™”
    def __init__(self, n):
        self.maxCount = n
        self.data = [None] * n
        self.count = 0
        self.front = -1
        self.rear = -1'

# ν˜„μž¬ 큐 길이λ₯Ό λ°˜ν™˜
    def size(self):
        return self.count

# 큐가 λΉ„μ–΄μžˆλŠ”μ§€ 
    def isEmpty(self):
        return self.count == 0

# 큐가 꽉 μ°¨μžˆλŠ”μ§€
    def isFull(self):
        return self.count == self.maxCount

# 데이터 μ›μ†Œ μΆ”κ°€
    def enqueue(self, x):
        if self.isFull():
            raise IndexError('Queue full')
        
        self.rear = (self.rear + 1) % self.maxCount
        self.data[self.rear] = x
        self.count += 1

#데이터 μ›μ†Œ 제거
    def dequeue(self):
        if self.isEmpty():
            raise IndexError('Queue empty')

        self.front = (self.front + 1) % self.maxCount
        x = self.data[self.front]
        self.count -= 1
        return x

# 큐의 맨 μ•ž μ›μ†Œ λ°˜ν™˜
    def peek(self):
        if self.isEmpty():
            raise IndexError('Queue empty')
        return self.data[(self.front + 1) % self.maxCount]
#μ—°μ‚°μ˜ μ •μ˜
size() : ν˜„μž¬ 큐에 λ“€μ–΄ μžˆλŠ” 데이터 μ›μ†Œμ˜ 수λ₯Ό ꡬ함
isEmpty() : ν˜„μž¬ 큐가 λΉ„μ–΄ μžˆλŠ”μ§€λ₯Ό νŒλ‹¨
isFull() : 큐에 데이터 μ›μ†Œκ°€ κΌ­ μ°¨ μžˆλŠ”μ§€λ₯Ό νŒλ‹¨
qneueue(x) : 데이터 μ›μ†Œ xλ₯Ό 큐에 μΆ”κ°€
dequeue() : 큐의 맨 μ•žμ— μ €μž₯된 데이터 μ›μ†Œλ₯Ό 제거(λ˜ν•œ, λ°˜ν™˜)
peek() : 큐의 맨 μ•žμ— μ €μž₯된 데이터 μ›μ†Œλ₯Ό λ°˜ν™˜(μ œκ±°ν•˜μ§€ μ•ŠμŒ)

 

μš°μ„ μˆœμœ„ 큐(Priority Queue)

일반적인 큐(Queue)λŠ” First in-First Out κ΅¬μ‘°μ΄λ‚˜, μš°μ„ μˆœμœ„ 큐(Priority Queue)λŠ” λ“€μ–΄κ°„ μˆœμ„œμ— 상관없이 μš°μ„ μˆœμœ„κ°€ 높은 데이터가 λ¨Όμ € λ‚˜μ˜€λŠ” 것을 λ§ν•œλ‹€. μš°μ„ μˆœμœ„ νλŠ” νž™(Heap)μ΄λΌλŠ” 자료ꡬ쑰λ₯Ό κ°€μ§€κ³  κ΅¬ν˜„ν•  수 μžˆλ‹€.

 

BELATED ARTICLES

more