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
์์ ์ญ์
- 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
- Time complexity
๋ ๋ฆฌ์คํธ ํฉ์น๊ธฐ 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
๋ฐ์
- ๊ฝ ์ฐฌ ์คํ์ push(x)๋ก ์์๋ฅผ ๋ ์ถ๊ฐํ๋ ค๊ณ ํ ๋
- pop()
- ๋น์ด์๋ ์คํ์์ pop()์ผ๋ก ์๋ ์์๋ฅผ ๊บผ๋ด๋ ค ํ ๋
stack underflow
๋ฐ์
- ๋น์ด์๋ ์คํ์์ pop()์ผ๋ก ์๋ ์์๋ฅผ ๊บผ๋ด๋ ค ํ ๋
- 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
(์ด๋ ต๊ฑฐ๋ ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ ๋ฑ ๋ค์ ํ์ธํ ๊ฒ๋ค)
member field, member method
- ์ฉ์ด์ ๋ป์ ์์ง๋ง ์ ๋งคํด์ ๋ค์ ์ ๋ฆฌํ๊ธฐ ์ํด ์ฐพ์๋ด
์ ๋ฆฌ์ ์ฐธ๊ณ ํ ์ฌ์ดํธ
- ์ฉ์ด์ ๋ป์ ์์ง๋ง ์ ๋งคํด์ ๋ค์ ์ ๋ฆฌํ๊ธฐ ์ํด ์ฐพ์๋ด
์ถ์์ ์๋ฃ๊ตฌ์กฐ
- abstract data type vs. data structure
- an ADT (Abstract Data Type) is more of a logical description, while a Data Structure is concrete.
- ์ ๋ฆฌ์ ์ฐธ๊ณ ํ ์ฌ์ดํธ : ์ถ์์ ์๋ฃํ vs. ์๋ฃ๊ตฌ์กฐ
- abstract data type vs. data structure
dummy node๋ฅผ ์ถ๊ฐํ ๊ตฌ์กฐ์ linked list
stack underflow
โผ๏ธย ๋๋ ์
์ค๋์ ๋ ๊ฐ์ง ๊ตํ(?) ์ ์ป์๋ค.
ํ๋ฒ์ ๋๊ฐ์ง ์ผ์ ํ์ง ์๊ธฐ ๊ฐ์๋ฅผ ๋ค์ผ๋ฉด์ TIL์ ์ ์ผ๋ ค๊ณ ํ๋๋ฐ, ์ธ๋ ค ๋ ์ ์ ์๊ณ ํ๋ค์๋ค. ๊ฐ์ ๋ฃ๋ ์ค๊ฐ์ ์ ๋ค ๋ณด๋, ๊ทธ๋ฅ ๋ฐ์์ฐ๊ธฐ๊ฐ ๋๋๊ฒ๋ ๋ณ๋ก์๋ค. ํฐ ์ฃผ์ (์ค๋ ๊ฐ์ ๊ฒฝ์ฐ LinkedList / Stack)๋ฅผ ๋ค ๋ฃ๊ณ ์ ๋ฆฌํ๋๊ฒ ๋์ ๋ฏ!
์ฌ์ํ ์ค์ ํ์ง ์๊ณ ๊ผผ๊ผผํ๊ฒ ์ฒดํฌํ๊ธฐ ์ค๋ ์ฐ์ต๋ฌธ์ ๋ฅผ ํ๋ฉด์
node.data ๋์ node ๊ฐ์ฒด๋ฅผ ๋ฐํํจ linked list์ nodeCount ์ฆ๊ฐ์ํค๋๊ฑธ ๋นผ๋จน์
๋ช ์๋ ์กฐ๊ฑด์ ๋นผ๋จน๋ ์ค์๋ฅผ ์ ์ง๋ฌ์ ๋๋ฒ๊น ํ๋ค๊ณ ๋ค ํฉํด์ ํ์๊ฐ ๊ฐ๊น์ด ์๋ชจํ๋ค. ๋ชฐ๋ผ์ ๋ชป ํธ๋๊ฒ ๋ณด๋ค ์ด๋ฐ ๋ถ๋ถ์์ ๊ผผ๊ผผํ์ง ๋ชปํด์ ๋ชป ํธ๋๊ฒ ๋ ์ซ๋ค. ์ฌ์ง์ด ์๋๋ ๊ทธ๋ ๊ฒ ์์ฃผ ํ๋ ์ค์๋ ์๋์ด์ ์์กด์ฌ์ด ๋ ์ํ๋ค. ใ ใ
๊ทธ๋๋ ์ด๋ฐ ๋ ์ด ์์ด์ผ ์์ผ๋ก ์ ๊ทธ๋ด ์ ์์ผ๋๊น ๊ณ์ ๋ด์๋์ง๋ ๋ง์์ผ์ง!
๋ด์ผ์ ๊ฐ์์ ์ค์ต์ ๊ผผ๊ผผํ๊ฒ ์งํํ๊ณ , ๋ด๊ฐ ์ดํดํ ๋ด์ฉ์ ํ ๋๋ก TIL์ ์ ์ ์ด๋ด์ผ๊ฒ ๋ค. :>. ๊ทธ๋ฆฌ๊ณ ๋ด์ผ์ github ๋ธ๋ก๊ทธ์ ์ฌ๋ ค๋ด์ผ์ง! ๐ฅย ์ด๋ ต์ง๋ง ํ ๋งํ ๊ฐ์น๊ฐ ์์ด๋ณด์ธ๋ค ๐