배열 | 연결리스트 | |
---|---|---|
저장공간 | 연속한 위치 | 임의의 위치 |
특정원소지칭 | 매우 간편 | 선형탐색과 유사 |
big-O | O(1) | O(n) |
특정원소 참조
리스트 순회
리스트 길이 얻어내기
원소 삽입
구현절차
newNode가 삽입되고자 하는 pos위치의 이전에 있는 node를 prev라고 하고 이후에 있는 node를 next라고 하자.
원소 삭제
두 리스트 합치기
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
# 1. 특정 원소 참조 - pos 번째에 있는 노드를 리턴한다
def getAt(self, pos):
# 연결리스트 범위에 벗어나면 None 리턴한다
if pos <= 0 or pos > self.nodeCount:
return None
# 인덱스를 만들고 인덱스가 pos만큼 다다를때까지 순환하고 마지막 curr를 리턴한다.
i = 0
curr = self.head
while i < pos:
curr = curr.next
i += 1
return curr
# 2. 리스트 순회
def traverse(self):
tlist = []
if self.nodeCount == 0: return tlist
curr = self.head
while True:
# 노드 자체가 아니라 노드의 데이터를 넣어야한다...
tlist.append(curr.data)
curr = curr.next
if curr is None:
break
return tlist
# 4. 원소 삽입
def insertAt(self, pos, newNode):
# pos가 가리키는 위치에 NewNode를 삽입, 성공과 실패에 따라 True나 False를 리턴
# pos의 범위가 유효한지 체크
if pos < 1 or pos > self.nodeCount + 1:
return False
# 맨 앞에 놓는 경우
if pos == 1:
newNode.next = self.head
self.head = newNode
# 맨 뒤에 놓는 경우
elif pos == nodeCount + 1:
self.tail.next = newNode
self.tail = newNode
else:
prev = getAt(pos -1)
newNode.next = prev.next
prev.next = newNode
self.nodeCount += 1
return True
# 5. 원소 삭제
def popAt(self, pos):
if pos < 1 or pos > self.nodeCount:
raise IndexError
curr = None
if pos == 1:
curr = self.head
if self.nodeCount == 1:
self.head = None
self.tail = None
else:
self.head = self.head.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
# 6. 두 리스트 합치기
def concat(self, L):
self.tail.next = L.head.next
if L.tail:
self.tail = L.tail
self.nodeCount += L.nodeCount
이와 같이 구현한 연결리스트는 인덱스로 위치를 찾으려면 그 인덱스까지 탐색해야하므로 탐색에는 비효율적이므로 보완하기 위한 변형된 연결리스트를 생성한다.
class Node:
def __init__(self, item):
self.data = item
self.next = None
class LinkedList:
def __init__(self):
self.nodeCount = 0
self.head = Node(None)
self.tail = None
self.head.next = self.tail
def __repr__(self):
if self.nodeCount == 0:
return 'LinkedList: empty'
s = ''
curr = self.head
while curr.next:
curr = curr.next
s += repr(curr.data)
if curr.next is not None:
s += ' -> '
return s
def getLength(self):
return self.nodeCount
def traverse(self):
result = []
curr = self.head
while curr.next:
curr = curr.next
result.append(curr.data)
return result
def getAt(self, pos):
if pos < 0 or pos > self.nodeCount:
return None
i = 0
curr = self.head
while i < pos:
curr = curr.next
i += 1
return curr
def insertAfter(self, prev, newNode):
newNode.next = prev.next
if prev.next is None:
self.tail = newNode
prev.next = newNode
self.nodeCount += 1
return True
def insertAt(self, pos, newNode):
if pos < 1 or pos > self.nodeCount + 1:
return False
if pos != 1 and pos == self.nodeCount + 1:
prev = self.tail
else:
prev = self.getAt(pos - 1)
return self.insertAfter(prev, newNode)
def concat(self, L):
self.tail.next = L.head.next
if L.tail:
self.tail = L.tail
self.nodeCount += L.nodeCount
class Node:
def __init__(self, item):
self.data = item
self.prev = None
self.next = None
class DoublyLinkedList:
def __init__(self):
self.nodeCount = 0
self.head = Node(None)
self.tail = Node(None)
self.head.prev = None
self.head.next = self.tail
self.tail.prev = self.head
self.tail.next = None
# 역방향으로 조회
def reverse(self):
result = []
if self.nodeCount == 0: return result
curr = self.tail.prev
while curr.prev:
result.append(curr.data)
curr = curr.prev
return result
# k번째 노드 반환
def getAt(self, pos):
if pos < 0 or pos > self.nodeCount:
return None
if pos > self.nodeCount // 2:
i = 0
curr = self.tail
while i < self.nodeCount - pos + 1:
curr = curr.prev
i += 1
else:
i = 0
curr = self.head
while i < pos:
curr = curr.next
i += 1
return curr
# prev node뒤에 새로운 노드 추가
def insertAfter(self, prev, newNode):
next = prev.next
newNode.prev = prev
newNode.next = next
prev.next = newNode
next.prev = newNode
self.nodeCount += 1
return True
# pos번째에 새로운 노드 추가 (insertAfter를 활용)
def insertAt(self, pos, newNode):
if pos < 1 or pos > self.nodeCount + 1:
return False
prev = self.getAt(pos - 1)
return self.insertAfter(prev, newNode)
# next 노드 뒤에 새로운 노드 추가
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
# prev노드 다음 노드를 삭제하고 그의 값을 반환
def popAfter(self, prev):
curr = prev.next
next = curr.next
prev.next = next
next.prev = prev
self.nodeCount -= 1
return curr.data
# next노드 이전 노드를 삭제하고 그의 값을 반환
def popBefore(self, next):
curr = next.prev
prev = curr.prev
prev.next = next
next.prev = prev
self.nodeCount -= 1
return curr.data
# pos위치의 노드를 삭제하고 그의 값을 반환
def popAt(self, pos):
if pos < 1 or pos > self.nodeCount:
raise IndexError
prev = self.getAt(pos - 1)
return self.popAfter(prev)
# 주어진 리스트를 이어붙인다
def concat(self, L):
prev = self.tail.prev
next = L.head.next
prev.next = next
next.prev = prev
self.tail = L.tail
self.nodeCount += L.nodeCount
class ArrayStack:
def __init__(self):
self.data = []
def size(self):
return len(self.data)
def isEmpty(self):
return self.size() == 0
def push(self, item):
self.data.append(item)
def pop(self):
return self.data.pop()
def peek(self):
return self.data[-1]
def splitTokens(exprStr):
tokens = []
val = 0
valProcessing = False
for c in exprStr:
if c == ' ':
continue
if c in '0123456789':
val = val * 10 + int(c)
valProcessing = True
else:
if valProcessing:
tokens.append(val)
val = 0
valProcessing = False
tokens.append(c)
if valProcessing:
tokens.append(val)
return tokens
def infixToPostfix(tokenList):
prec = {
'*': 3,
'/': 3,
'+': 2,
'-': 2,
'(': 1,
}
opStack = ArrayStack()
postfixList = []
for t in tokenList:
if t == '(':
opStack.push(t)
elif t == ')':
while opStack.peek() != '(':
postfixList.append(opStack.pop())
opStack.pop()
elif type(t) is int:
postfixList.append(t)
else:
while not opStack.isEmpty() and prec[opStack.peek()] >= prec[t]:
postfixList.append(opStack.pop())
opStack.push(t)
while not opStack.isEmpty():
postfixList.append(opStack.pop())
return postfixList
def postfixEval(tokenList):
opStack = ArrayStack()
for t in tokenList:
if type(t) is int:
opStack.push(t)
else:
right = opStack.pop()
left = opStack.pop()
val = 0
if t == '+':
val = left + right
elif t == '-':
val = left - right
elif t == '*':
val = left * right
elif t == '/':
val = left / right
opStack.push(val)
return opStack.pop()
def solution(expr):
tokens = splitTokens(expr)
postfix = infixToPostfix(tokens)
val = postfixEval(postfix)
return val