Day 2

TIL - LinkedList & Stack

๐Ÿ“‹ย ๊ณต๋ถ€ ๋‚ด์šฉ

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ Linked List

  • ์ถ”์ƒ์  ์ž๋ฃŒ๊ตฌ์กฐ Abstract Data Structures

    • ๋‚ด๋ถ€ ๊ตฌํ˜„์—๋Š” ์‹ ๊ฒฝ์“ธ ํ•„์š” ์—†๋Š” ๊ตฌ์กฐ
    • data & a set of operations
    • ์ด ๋‘ ๊ฐ€์ง€๋ฅผ ์ถ”์ƒ์ ์œผ๋กœ ๋ณด์—ฌ์คŒ
  • Linke List?

    • Node๊ฐ€ ์„ ํ˜•์ ์œผ๋กœ ์—ฐ๊ฒฐ๋œ ๊ตฌ์กฐ
  • Node & LinkedList ๊ตฌํ˜„

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
     class Node:
     	def __init__(self, item):
     		self.data = item
     		self.next = None # ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
    
     class LinkedList:
     	def __init__(self):
     		self.nodeCount = 0 # ๋…ธ๋“œ์˜ ์ด ๊ฐฏ์ˆ˜
     		self.head = None # ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ
     		self.tail = None # ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ
    
  • Linked List ์—ฐ์‚ฐ (operations)

    linked list์˜ index๋Š” 1๋ถ€ํ„ฐ ์‹œ์ž‘ / 0์€ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์‚ฌ์šฉ(Dummy node)

    (์‹ค์Šต์œผ๋กœ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋งŒ ์ฒจ๋ถ€ํ–ˆ์Œ)
    • kth element ์ฐธ์กฐ

    • ๋ฆฌ์ŠคํŠธ ์ˆœํšŒ

      1
      2
      3
      4
      5
      6
      7
      
       def traverse(self):
               curr = self.head
               returnList = []
               while curr is not None: 
                   returnList.append(curr.data)
                   curr = curr.next
               return returnList
      
    • ๊ธธ์ด ์–ป๊ธฐ

    • ์›์†Œ ์‚ฝ์ž…

      • Time complexity
        • ๋งจ ์•ž์— ์‚ฝ์ž… : O(1)
        • ์ค‘๊ฐ„์— ์‚ฝ์ž… : O(n)
        • ๋งจ ๋์— ์‚ฝ์ž… : (Tail pointer๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—) O(1)
    • ์›์†Œ ์‚ญ์ œ

      • Time complexity
        • ๋งจ ์•ž์— ์‚ฝ์ž… : O(1)
        • ์ค‘๊ฐ„์— ์‚ฝ์ž… : O(n)
        • ๋งจ ๋์— ์‚ฝ์ž… : O(n) โ†’ ์ด ์ƒํ™ฉ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉ
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      
         # ์‚ญ์ œํ•œ node ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜
         def popAt(self, pos):
         	if pos < 1 or pos > self.nodeCount:
         	  raise IndexError
      
         	if pos == 1:
         	  prev = None
         	  curr = self.head
         	  self.head = curr.next
         	else:
             prev = self.getAt(pos - 1)
             curr = prev.next
             prev.next = curr.next
      
         	if pos == self.nodeCount:
             self.tail = prev
      
         	self.nodeCount -= 1
         	return curr.data
      
    • ๋‘ ๋ฆฌ์ŠคํŠธ ํ•ฉ์น˜๊ธฐ concat

  • ๋ฐฐ์—ด Array vs ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ Linked List

    ๋ฐฐ์—ด์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ
    ์ €์žฅ ๊ณต๊ฐ„์—ฐ์†๋œ ์œ„์น˜์ž„์˜์˜ ์œ„์น˜
    ํŠน์ • ์›์†Œ ์ฐธ์กฐ๋งค์šฐ ๊ฐ„ํŽธ์„ ํ˜•ํƒ์ƒ‰๊ณผ ์œ ์‚ฌ
    O(1)O(n)

    time complexity์— ๋ถˆ๋ฆฌํ•จ์ด ์žˆ๋Š”๋ฐ๋„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?

  • ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ Linked List์˜ ํž˜

    • ์œ ์—ฐํ•œ ์‚ฝ์ž… ๋ฐ ์‚ญ์ œ
    • Head, Tail์— dummy node๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฐ„ํŽธํ•˜๊ณ  ์ง๊ด€์ ์ธ ์„ค๊ณ„ ๊ฐ€๋Šฅ
    • ์ถ”๊ฐ€ ๊ตฌํ˜„ operations
      • insertAfter(prev, node)

      • popAfter(prev) & popAt(pos)

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        
        def popAfter(self, prev):
        	curr = prev.next
        	if curr is None : 
            return None
        	if curr.next is None:
            self.tail = prev
        
        	prev.next = curr.next
        	self.nodeCount -= 1 # nodeCount ๊ผญ ์ฒดํฌํ•˜๊ธฐ
        
        	return curr.data
        
        def popAt(self, pos):
          if pos < 1 or pos > self.nodeCount:
            raise IndexError
        
          prev = self.getAt(pos-1)
          return self.popAfter(prev)
        

์–‘๋ฐฉํ–ฅ / ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ Double Linked List

  • ์–‘์ชฝ์œผ๋กœ ์—ฐ๊ฒฐ๋œ link - next node, previous node๋กœ ๋‘ ๋ฐฉํ–ฅ ๋ชจ๋‘ ์ง„ํ–‰ ๊ฐ€๋Šฅ - ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋Š˜์–ด๋‚˜์ง€๋งŒ, ์•ž์—์„œ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋’ค์—์„œ๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐพ์•„๊ฐˆ ์ˆ˜ ์žˆ๋‹ค๋Š”๊ฒŒ ์žฅ์ 
    • getAt() ํ•จ์ˆ˜ ๋˜ํ•œ pos๊ฐ€ ์ค‘๊ฐ„๊ฐ’ ์ด์ƒ์ผ ๋•Œ๋Š” ๋’ค์—์„œ๋ถ€ํ„ฐ ์ฐพ๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ
  • operations
    • reverse

      1
      2
      3
      4
      5
      6
      7
      
      def reverse(self):
          result = []
          curr = self.tail
          while curr.prev.prev:
              curr = curr.prev
              result.append(curr.data)
          return result
      
    • insertBefore

      1
      2
      3
      4
      5
      6
      7
      8
      
      def insertBefore(self, next, newNode):
          prev = next.prev
          newNode.next = next
          newNode.prev = prev
          prev.next = newNode
          next.prev = newNode
          self.nodeCount += 1
      		return True
      
    • popAfter, popBefore, popAt

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      
      def popAfter(self, prev):
          curr = prev.next
          next = curr.next
          prev.next = next
          next.prev = prev
          self.nodeCount -= 1
          return curr.data
      
      def popBefore(self, next):
          curr = next.prev
          prev = curr.prev
          prev.next = next
          next.prev = prev
          self.nodeCount -= 1
          return curr.data
      
      def popAt(self, pos):
          if pos < 1 or pos > self.nodeCount:
              raise IndexError
          prev = self.getAt(pos - 1)
          return self.popAfter(prev)
      
          # next = self.getAt(pos+1) # getAt ํ•จ์ˆ˜๊ฐ€ pos == nodeCount+1 ์ผ ๋•Œ ์ง€์›์„ ํ•˜์ง€ ์•Š์•„์„œ ์‚ฌ์šฉ์€ ์–ด๋ ค์›€
          # next = self.getAt(pos).next #๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
          # return self.popBefore(next)
      
    • concat(self, L)

      1
      2
      3
      4
      5
      6
      7
      
      def concat(self, L):
          lastNode = self.tail.prev
          firstNode = L.head.next
          lastNode.next = firstNode
          firstNode.prev = lastNode
          self.tail = L.tail
          self.nodeCount += L.nodeCount
      

์Šคํƒ Stack

  • data element๋ฅผ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ์„ ํ˜• ๊ตฌ์กฐ / LIFO
  • operations
    • size()
    • isEmpty()
    • push(x)
      • ๊ฝ‰ ์ฐฌ ์Šคํƒ์— push(x)๋กœ ์›์†Œ๋ฅผ ๋” ์ถ”๊ฐ€ํ•˜๋ ค๊ณ  ํ•  ๋•Œ stack overflow ๋ฐœ์ƒ
    • pop()
      • ๋น„์–ด์žˆ๋Š” ์Šคํƒ์—์„œ pop()์œผ๋กœ ์—†๋Š” ์›์†Œ๋ฅผ ๊บผ๋‚ด๋ ค ํ•  ๋•Œ stack underflow ๋ฐœ์ƒ
    • peek()
      • ๋ฐ์ดํ„ฐ ์ฐธ์กฐ, ์ œ๊ฑฐํ•˜์ง€๋Š” ์•Š์Œ
  • ์ถ”์ƒ์  ์ž๋ฃŒ๊ตฌ์กฐ๋กœ ๊ตฌํ˜„
    • Array ๋˜๋Š” LinkedList ์ด์šฉ
    • ๋งŒ๋“ค์–ด์ ธ์žˆ๋Š” Stack library ๋ฅผ import ํ•  ์ˆ˜๋„ ์žˆ์Œ from pythonds.basic.stack import Stack

  • ์Šคํƒ์˜ ์‘์šฉ 1) ํ›„์œ„ ํ‘œ๊ธฐ๋ฒ•์œผ๋กœ ๋ณ€ํ™˜

    • ์ค‘์œ„ ํ‘œ๊ธฐ๋ฒ• (infix notation) : (A+B) * (C+D) โ†’ ํ›„์œ„ ํ‘œ๊ธฐ๋ฒ• (postfix notation) : AB+CD+*
    • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ค๊ณ„
      • operator ์—ฐ์‚ฐ์ž๋ฅผ ์Šคํƒ์— ๋„ฃ๋Š” ๋ฐฉ์‹

      • ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„ ์„ค์ •

        1
        
        prec = {'*':3, '/':3, '+':2, '-':2, '(':1}
        
      • ๊ตฌํ˜„ ์ฝ”๋“œ

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        
        def solution(S):
            opStack = ArrayStack()
            charList = []  # ์ˆ˜์‹์„ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ์ €์žฅํ•œ ํ›„ .join์„ ํ†ตํ•ด ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜
        
            for s in S:
                if s in prec.keys():  # ์—ฐ์‚ฐ์ž + ์—ฌ๋Š” ๊ด„ํ˜ธ
                    if s == "(":
                        opStack.push(s)
                    else:
                        while not opStack.isEmpty():  # ์Šคํƒ์ด ๋น„์–ด์žˆ๋Š” ๋™์•ˆ ๊ณ„์†
                            if prec[opStack.peek()] >= prec[s]:  # ์Šคํƒ ๋งจ ์œ„์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๊ฑฐ๋‚˜ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋งŒ
                                charList.append(opStack.pop())  # pop()ํ•˜์—ฌ ๋ฌธ์ž์—ด์— ์ถœ๋ ฅ
                            else:
                                break
                        opStack.push(s)
        
                elif s == ")":  # ๋‹ซ๋Š” ๊ด„ํ˜ธ
                    while opStack.peek() != "(":  # ์—ฌ๋Š” ๊ด„ํ˜ธ๊ฐ€ ๋‚˜์˜ฌ๋•Œ๊นŒ์ง€ ๋ชจ๋“  ์—ฐ์‚ฐ์ž๋ฅผ ๊บผ๋‚ด ์ถœ๋ ฅ
                        charList.append(opStack.pop())
                    opStack.pop()  # pop '('
        
                else:  # ํ”ผ์—ฐ์‚ฐ์ž
                    charList.append(s)
        
            while not opStack.isEmpty():  # ์Šคํƒ์— ๋‚จ์•„์žˆ๋Š” ์—ฐ์‚ฐ์ž๋“ค์„ ๋ชจ๋‘ ์ถœ๋ ฅ
                charList.append(opStack.pop())
        
            answer = "".join(charList)
            return answer
        
  • ์Šคํƒ์˜ ์‘์šฉ 2) ํ›„์œ„ ํ‘œ๊ธฐ๋ฒ• ๊ณ„์‚ฐ

    • ์•ž์—์„œ๋ถ€ํ„ฐ ๋’ค๋กœ ์ฝ์–ด๋‚˜๊ฐ€๋ฉด์„œ ๋จผ์ € ๋งŒ๋‚˜๋Š” ์—ฐ์‚ฐ์ž๋ฅผ ๋จผ์ € ๊ณ„์‚ฐ
    • ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์„ค๊ณ„
      • operands ํ”ผ์—ฐ์‚ฐ์ž๋“ค์„ ์Šคํƒ์— ๋„ฃ๋Š” ๋ฐฉ์‹

      • ๊ตฌํ˜„ ์ฝ”๋“œ

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        
        def postfixEval(tokenList):
            valStack = ArrayStack()
        
            for t in tokenList:
                if type(t) is int:
                    valStack.push(t)
                else:
                    b = valStack.pop()
                    a = valStack.pop()
                    if t == '*':
                        valStack.push(a*b)
                    elif t == '/':
                        valStack.push(a/b)
                    elif t == '+':
                        valStack.push(a+b)
                    elif t == '-':
                        valStack.push(a-b)
        
            return valStack.pop()	
        

๐Ÿ‘€ย CHECK

(์–ด๋ ต๊ฑฐ๋‚˜ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ ๋œ ๊ฒƒ ๋“ฑ ๋‹ค์‹œ ํ™•์ธํ•  ๊ฒƒ๋“ค)

โ€ผ๏ธย ๋Š๋‚€ ์ 

์˜ค๋Š˜์€ ๋‘ ๊ฐ€์ง€ ๊ตํ›ˆ(?) ์„ ์–ป์—ˆ๋‹ค.

  1. ํ•œ๋ฒˆ์— ๋‘๊ฐ€์ง€ ์ผ์„ ํ•˜์ง€ ์•Š๊ธฐ ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉด์„œ TIL์„ ์ ์œผ๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, ์™ธ๋ ค ๋” ์ •์‹ ์—†๊ณ  ํž˜๋“ค์—ˆ๋‹ค. ๊ฐ•์˜ ๋“ฃ๋Š” ์ค‘๊ฐ„์— ์ ๋‹ค ๋ณด๋‹ˆ, ๊ทธ๋ƒฅ ๋ฐ›์•„์“ฐ๊ธฐ๊ฐ€ ๋˜๋Š”๊ฒƒ๋„ ๋ณ„๋กœ์˜€๋‹ค. ํฐ ์ฃผ์ œ (์˜ค๋Š˜ ๊ฐ™์€ ๊ฒฝ์šฐ LinkedList / Stack)๋ฅผ ๋‹ค ๋“ฃ๊ณ  ์ •๋ฆฌํ•˜๋Š”๊ฒŒ ๋‚˜์„ ๋“ฏ!

  2. ์‚ฌ์†Œํ•œ ์‹ค์ˆ˜ ํ•˜์ง€ ์•Š๊ณ  ๊ผผ๊ผผํ•˜๊ฒŒ ์ฒดํฌํ•˜๊ธฐ ์˜ค๋Š˜ ์—ฐ์Šต๋ฌธ์ œ๋ฅผ ํ’€๋ฉด์„œ

    node.data ๋Œ€์‹  node ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•จ linked list์˜ nodeCount ์ฆ๊ฐ์‹œํ‚ค๋Š”๊ฑธ ๋นผ๋จน์Œ

    ๋ช…์‹œ๋œ ์กฐ๊ฑด์„ ๋นผ๋จน๋Š” ์‹ค์ˆ˜๋ฅผ ์ €์งˆ๋Ÿฌ์„œ ๋””๋ฒ„๊น… ํ•œ๋‹ค๊ณ  ๋‹ค ํ•ฉํ•ด์„œ ํ•œ์‹œ๊ฐ„ ๊ฐ€๊นŒ์ด ์†Œ๋ชจํ–ˆ๋‹ค. ๋ชฐ๋ผ์„œ ๋ชป ํ‘ธ๋Š”๊ฒƒ ๋ณด๋‹ค ์ด๋Ÿฐ ๋ถ€๋ถ„์—์„œ ๊ผผ๊ผผํ•˜์ง€ ๋ชปํ•ด์„œ ๋ชป ํ‘ธ๋Š”๊ฒŒ ๋” ์‹ซ๋‹ค. ์‹ฌ์ง€์–ด ์›๋ž˜๋Š” ๊ทธ๋ ‡๊ฒŒ ์ž์ฃผ ํ•˜๋Š” ์‹ค์ˆ˜๋„ ์•„๋‹ˆ์–ด์„œ ์ž์กด์‹ฌ์ด ๋” ์ƒํ–ˆ๋‹ค. ใ… ใ… 
    ๊ทธ๋ž˜๋„ ์ด๋Ÿฐ ๋‚ ์ด ์žˆ์–ด์•ผ ์•ž์œผ๋กœ ์•ˆ ๊ทธ๋Ÿด ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ ๊ณ„์† ๋‹ด์•„๋‘์ง€๋Š” ๋ง์•„์•ผ์ง€!

๋‚ด์ผ์€ ๊ฐ•์˜์™€ ์‹ค์Šต์„ ๊ผผ๊ผผํ•˜๊ฒŒ ์ง„ํ–‰ํ•˜๊ณ , ๋‚ด๊ฐ€ ์ดํ•ดํ•œ ๋‚ด์šฉ์„ ํ† ๋Œ€๋กœ TIL์„ ์ž˜ ์ ์–ด๋ด์•ผ๊ฒ ๋‹ค. :>. ๊ทธ๋ฆฌ๊ณ  ๋‚ด์ผ์€ github ๋ธ”๋กœ๊ทธ์— ์˜ฌ๋ ค๋ด์•ผ์ง€! ๐Ÿ”ฅย ์–ด๋ ต์ง€๋งŒ ํ•  ๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ์–ด๋ณด์ธ๋‹ค ๐Ÿ˜Š

Hugo๋กœ ๋งŒ๋“ฆ
Jimmy์˜ Stack ํ…Œ๋งˆ ์‚ฌ์šฉ ์ค‘