[자료ꡬ쑰] μŠ€νƒ(Stack)

2022. 3. 10. 16:05

πŸ“ŒκΈ°μˆ λ©΄μ ‘ 질문

Q. μŠ€νƒ(Stack)에 λŒ€ν•΄ μ„€λͺ…ν•˜κ³  μ˜ˆμ œμ†ŒμŠ€λ₯Ό κ΅¬ν˜„ν•΄λ³΄μ•„λΌ

Q. μŠ€νƒκ³Ό 큐의 μ°¨μ΄λŠ” λ¬΄μ—‡μΌκΉŒμš”?

Q. ν™”μ΄νŠΈλ³΄λ“œμ— 큐둜 μŠ€νƒμ„ κ΅¬ν˜„ν•΄ 보라. (λ„₯슨)

Q. μŠ€νƒκ³Ό λ§ν¬λ“œλ¦¬μŠ€νŠΈμ™€ 리슀트의 차이점을 μ„€λͺ…ν•΄ λ³΄μ„Έμš”. (넀이버)

Q. μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°κ°€ μ™œ μΌμ–΄λ‚˜λŠ”κ°€?

 

Stack


  • μŠ€νƒ : ν•œ μͺ½ λμ—μ„œλ§Œ 자료λ₯Ό λ„£κ³  λΊ„ 수 μžˆλŠ” μ„ ν˜• 자료ꡬ쑰
  • κ°€μž₯ λ§ˆμ§€λ§‰μ— λ“€μ–΄μ˜¨ 데이터가 κ°€μž₯ λ¨Όμ € λ‚˜κ°€λŠ” LIFO(Last In First Out)방식을 μ‚¬μš©
  • μŠ€νƒκ³΅κ°„μ΄ 가득찼을 λ•Œ 데이터λ₯Ό 더 λ„£μœΌλ €κ³  ν•  경우 ν”„λ‘œκ·Έλž¨μ— 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것을 Overflow μƒνƒœλΌκ³  ν•˜λ©°, λ°˜λŒ€λ‘œ μŠ€νƒ μ €μž₯곡간에 데이터가 μ—†λŠ”λ° ν”„λ‘œκ·Έλž¨μ—μ„œ μŠ€νƒμ—μ„œ 데이터λ₯Ό κΊΌλ‚΄λ €κ³  ν•  경우 ν”„λ‘œκ·Έλž¨μ— 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것을 Underflow μƒνƒœλΌκ³  함
  • μ‚½μž…(Push)κ³Ό 제거(Pop)λŠ” λͺ¨λ‘ Topμ΄λΌλŠ” μŠ€νƒμ˜ ν•œμͺ½ λμ—μ„œλ§Œ 일어남

 

μŠ€νƒμ˜ κ΅¬ν˜„ : μ—°μ‚°


μŠ€νƒμ€ μ•„λž˜ μ—°μ‚°λ“€λ‘œ 좔상화할 수 μžˆλ‹€.

  • push - μŠ€νƒ λ§¨μœ„μ— ν•­λͺ©μ„ μ‚½μž…
  • pop - μŠ€νƒ λ§¨μœ„μ— ν•­λͺ© μ‚­μ œ
  • peek - μŠ€νƒμ˜ 맨 μœ„(top)λ₯Ό ν‘œμ‹œ (읽기 : 원본이 μœ μ§€λ¨)
  • isEmpty - μŠ€νƒμ΄ λΉ„μ–΄μžˆλŠ”μ§€ 확인
  • isFull - μŠ€νƒμ΄ 가득 μ°¨ μžˆλŠ”μ§€ 확인
  • getSize - μŠ€νƒμ— μžˆλŠ” μš”μ†Œ 수λ₯Ό λ°˜ν™˜

 

κΈ°λ³Έλ™μž‘


Push

데이터λ₯Ό μŠ€νƒμ— λ„£λŠ” μž‘μ—…μ„ push λΌκ³  ν•œλ‹€. pushλŠ” λ‹€μŒ 단계λ₯Ό κ±°μΉœλ‹€.

  • 1 단계 - μŠ€νƒμ΄ 가득 μ°ΌλŠ” μ§€ 확인
  • 2 단계 - μŠ€νƒμ΄ 가득 μ°¨λ©΄ 였λ₯˜κ°€ λ°œμƒν•˜κ³  μ’…λ£Œλœλ‹€.
  • 3 단계 - μŠ€νƒμ΄ 가득 μ°¨μ§€ μ•ŠμœΌλ©΄ Top을 μ¦κ°€μ‹œν‚¨λ‹€.
  • 4 단계 - Top이 κ°€λ¦¬ν‚€λŠ” μŠ€νƒ μœ„μΉ˜μ— 데이터λ₯Ό μΆ”κ°€ν•œλ‹€.

 

Pop

데이터λ₯Ό μŠ€νƒμ— μ œκ±°ν•˜λŠ” μž‘μ—…μ„ pop이라고 ν•œλ‹€. pop은 λ‹€μŒ 단계λ₯Ό κ±°μΉœλ‹€.

  • 1 단계 - μŠ€νƒμ΄ λΉ„μ–΄ μžˆλŠ”μ§€ ν™•μΈν•œλ‹€.
  • 2 단계 - μŠ€νƒμ΄ λΉ„μ–΄ 있으면 였λ₯˜κ°€ λ°œμƒν•˜κ³  μ’…λ£Œν•œλ‹€.
  • 3 단계 - μŠ€νƒμ΄ λΉ„μ–΄ μžˆμ§€ μ•ŠμœΌλ©΄ Top μ΄ κ°€λ¦¬ν‚€λŠ” λ°μ΄ν„°λ₯Ό μ œκ±°ν•œλ‹€.
  • 4 단계 - Top 값을 κ°μ†Œμ‹œν‚¨λ‹€.
  • 5 단계 - 성곡을 λ°˜ν™˜ν•œλ‹€.

 

μ‹œκ°„λ³΅μž‘λ„ (Time Complexity)


 

  • push(), pop()의 μ‹œκ°„λ³΅μž‘λ„λŠ” 늘 O(1) : μ‚½μž…, μ‚­μ œκ°€ 항상 Topμ—μ„œλ§Œ μΌμ–΄λ‚˜κΈ° λ•Œλ¬Έ
  • search()의 μ‹œκ°„λ³΅μž‘λ„ O(n) : νŠΉμ • 데이터λ₯Ό 찾을 λ•ŒλŠ” νŠΉμ • 데이터λ₯Ό 찾을 λ•ŒκΉŒμ§€ μˆ˜ν–‰μ„ ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έ

 

κ΅¬ν˜„


κ΅¬ν˜„ λ°©λ²•μ—λŠ” 두 κ°€μ§€κ°€ μžˆλ‹€.

λ°°μ—΄ μ‚¬μš© (Cμ–Έμ–΄ λ“±)

  • μž₯점 : κ΅¬ν˜„ν•˜κΈ° 쉬움
  • 단점 : 크기가 동적이 μ•„λ‹˜. λŸ°νƒ€μž„μ‹œ ν•„μš”μ— 따라 λŠ˜κ±°λ‚˜ 쀄지 μ•ŠμŒ

μ—°κ²°λ¦¬μŠ€νŠΈ μ‚¬μš©

  • μž₯점 : 크기가 λ™μ μž„. λŸ°νƒ€μž„μ‹œ ν•„μš”μ— 따라 크기가 ν™•μž₯ 및 μΆ•μ†Œλ  수 있음
  • 단점 : 포인터λ₯Ό μœ„ν•œ μΆ”κ°€ λ©”λͺ¨λ¦¬ 곡간이 ν•„μš”ν•¨

 

class Stack:
	def __int__(self):                   # 데이터 μ €μž₯을 μœ„ν•œ 리슀트 μ€€λΉ„ ([special method](https://www.notion.so/special-method-c7a701bed79c4e1ea37a5231ac996af1))
		self.items = []

	def push(self, val):
		self.items.append(val)

	def pop(self):
		try
			return self.items.pop()  
		except IndexError:                  # popν•  μ•„μ΄ν…œμ΄ μ—†μœΌλ©΄
			print("Stack is empty")           # indexError λ°œμƒ

	def peek(self):
		try:
			return self.items[-1]
		except IndexError:
			print("Stack is empty")
	
	def __len__(self):                     # len()둜 ν˜ΈμΆœν•˜λ©΄ stack의 item 수 λ°˜ν™˜
		return len(self.items)

 

 

μŠ€νƒμ˜ ν™œμš©


예제 1. κ΄„ν˜Έ 검사

stack을 μ΄μš©ν•΄μ„œ ν‘ΈλŠ” 기본적이고 λŒ€ν‘œμ μΈ 문제

❓ μ£Όμ–΄μ§„ μž…λ ₯μ—μ„œ κ΄„ν˜Έ {}, ()κ°€ μ œλŒ€λ‘œ 짝을 μ΄λ€˜λŠ”μ§€ κ²€μ‚¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ λ§Œλ“œμ‹œμ˜€. - 예λ₯Ό λ“€μ–΄ {( )}λŠ” μ œλŒ€λ‘œ 된 μ§μ΄μ§€λ§Œ, {( })λŠ” μ œλŒ€λ‘œ 된 짝이 μ•„λ‹ˆλ‹€. - μž…λ ₯은 ν•œ μ€„μ˜ 파이썬 μ½”λ“œμΌμˆ˜λ„ 있고, κ΄„ν˜Έλ§Œ μ£Όμ–΄μ§ˆ μˆ˜λ„ μžˆλ‹€. - μ •μƒμ μœΌλ‘œ 짝을 이룬 경우 1, κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ 0을 좜λ ₯ν•œλ‹€. - print(‘{‘) 같은 κ²½μš°λŠ” μž…λ ₯으둜 μ£Όμ–΄μ§€μ§€ μ•ŠμœΌλ―€λ‘œ κ³ λ €ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€. - 각 μ€„λ§ˆλ‹€ "#T" (TλŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€ 번호)λ₯Ό 좜λ ₯ν•œ λ’€, 닡을 좜λ ₯ν•œλ‹€.

μ˜ˆμ‹œ

좜λ ₯

3
print({} {}'.format(1,2))
N, M = map(int, input(), split())
print('#{} {}'.format(tc, find())
#1 1
#2 1
#3 0

μ½”λ“œ

def bracket_check(val):                          # κ΄„ν˜Έμ˜ 짝 λ”•μ…”λ„ˆλ¦¬
    matching_dict = {'}': '{', ')': '('}
    stack = []

    for i in val:
        if i in ('{', '('):                      # μ—΄λ¦° κ΄„ν˜Έλ₯Ό 찾으면 μŠ€νƒμ— push
            stack.append(i)

        elif i in ('}', ')'):                    # λ‹«νžŒ κ΄„ν˜Έλ₯Ό 찾으면              
            if not stack or stack[len(stack) - 1] != matching_dict[i]:         # μŠ€νƒμ΄ λΉ„μ–΄μžˆκ±°λ‚˜ κ΄„ν˜Έμ˜ 짝이 λ§žμ§€ μ•ŠμœΌλ©΄
                return 0
            else:
								stack.pop()  # 짝이 맞으면 pop

    if stack:                                      # 검사 후에도 μŠ€νƒμ— κ΄„ν˜Έκ°€ 남아 있으면
        return 0
    else:
        return 1

T = int(input())
for tc in range(T):
    print('#%d %d' % (tc + 1, bracket_check(input())))

 

예제 2 : ν›„μœ„ ν‘œκΈ° μˆ˜μ‹μ˜ 계산

μ€‘μœ„ ν‘œκΈ°λ²•κ³Ό ν›„μœ„ ν‘œκΈ°λ²•

  • μ€‘μœ„ ν‘œκΈ°λ²• (infix notation)
    • μš°λ¦¬κ°€ μΌμƒμ—μ„œ μ‚¬μš©ν•˜λŠ” μˆ˜μ‹μ˜ ν‘œκΈ°λ²•
    • μ—°μ‚°μžκ°€ ν”Όμ—°μ‚°μžλ“€μ˜ μ‚¬μ΄μ— μœ„μΉ˜
  • (A + B) * (C + D)
  • ν›„μœ„ ν‘œκΈ°λ²• (postfix notation)
    • 컴퓨터가 μˆ˜μ‹μ„ κ³„μ‚°ν•˜λŠ”λ° μœ λ¦¬ν•¨
    • μ—°μ‚°μžκ°€ ν”Όμ—°μ‚°μžλ“€μ˜ λ’€μ— μœ„μΉ˜
  • A B + C D + *

 

-> μŠ€νƒμœΌλ‘œ κ΅¬ν˜„ν•  수 μžˆλŠ” λŒ€ν‘œμ μΈ μ˜ˆμ‹œλ‘œλŠ”

  1. μ€‘μœ„ ν‘œκΈ°λ²• μˆ˜μ‹μ„ ν›„μœ„ ν‘œκΈ°λ²• μˆ˜μ‹μœΌλ‘œ λ³€ν™˜ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜
  2. ν›„μœ„ ν‘œκΈ°λ²• μˆ˜μ‹μ„ κ³„μ‚°ν•˜λŠ” μ•Œκ³ λ¦¬μ¦˜

이 μžˆλ‹€.

 

⇒ 리슀트λ₯Ό ν™œμš©ν•˜μ—¬ 2. ν›„μœ„ ν‘œκΈ°λ²• μˆ˜μ‹μ„ κ³„μ‚°ν•˜λ©΄ λ‹€μŒκ³Ό κ°™λ‹€.

❓ μž…λ ₯: {“2”, “3”, “5”, “+”, “*”, “7”, “-“} 좜λ ₯: 10

κ΅¬ν˜„

def Calculate(tokens):
    stack = []
    for token in tokens:
        if token == '+':
            stack.append(stack.pop()+stack.pop())
        elif token == '-':
            stack.append(-(stack.pop()-stack.pop()))
        elif token == '*':
            stack.append(stack.pop()*stack.pop())
        elif token == '/':
            rv = stack.pop()
            stack.append(stack.pop()/rv)
        else:
            stack.append(int(token))
    return stack.pop()
 
print(Calculate(["2", "3", "5", "*", "+", "7", "-"]))

 

BELATED ARTICLES

more