본 포스팅은 아래의 출처를 참고하여 정리한 것입니다.
https://www.youtube.com/watch?v=PIidtIBCjEg&list=PLsMufJgu5933ZkBCHS7bQTx0bncjwi4PK&index=1
한방향 vs 양방향
배열과의 비교
연결리스트: 각각의 Node로 연결된 리스트
class Node:
def __init__(self, key=None):
self.key = key
self.next = None # link, default가 None
def __str__(self):
return str(self.key)
__str__
: print(v)
처럼 노드 자체를 출력 ➡️ 알아서 key 값을 출력print(v.__str__())
print(v.key)
a = Node(3)
b = Node(9)
c = Node(-1)
a.next = b
b.next = c
각 노드마다 변수를 할당해야 하는 번거로움 ➡️ 가장 앞 노드 Head Node만 정의해줌
# head Node와 linked list의 개수를 저장해놓은 size 또다른 class 정의
# 한방향 연결리스트의 객체
class SinglyLinkedList:
def __init__(self):
self.head = None # 처음에는 빈 리스트
self.size = 0 # 처음에는 비어있는 리스트
# 맨 앞 삽입 methods
def pushFront(self, key):
new_node = Node(key)
new_node.next = self.head # 현재 head node를 먼저 next로 만들어주고
self.head = new_node # 그 다음에 head node를 new_node로 재지정
self.size += 1
# 맨 뒤 삽입 methods
def pushBack(self, key):
v = Node(key)
if len(self) == 0: # 빈 리스트 ➡️ head node이자 tail node
self.head = v
else:
tail = self.head
while tail.next != None: # head node부터 next를 쫓으며 tail node까지 찾음
tail = tail.next
tail.next = v
self.size += 1
# 노드 개수 출력하는 길이 methods
def __len__(self):
return self.size
L = SinglyLinkedList()
L.pushFront(-1)
L.pushFront(9)
L.pushFront(3)
L.pushFront(5)
L.pushBack(4)
def popFront(self):
if len(self) == 0: # 지우고 싶은 노드가 없을 수 있음, empty list
return None
else: # 하나 이상의 노드 존재
x = self.head
key = self.key # return 해주기 위해 copy
self.head = x.next
self.size -= 1
del x # 메모리 상에서 객체 완전히 삭제
return key
def popBack(self):
if len(self) == 0 : return None
else:
# running technique
prev, tail = None, self.head # 징검다리처럼
while tail.next != None:
prev = tail
tail = tail.next
if len(self) == 1: # 리스트에 노드가 1개 -> 즉 head이면서 tail인 경우는 tail node가 삭제되면 head node는 None을 가리킴
self.head = None
else:
prev.next = None # or prev.next = tail.next
key = tail
self.size -= 1
del tail
return key
pushFront
, popFront
: pushBack
, popBack
: def search(self, key):
# key 값의 노드를 return, 없으면 None return
v = self.head
while v != None:
if v.key == key: return v
v = v.next
return None # or return v
__iterator__
선언def __iterator__(self):
v = self.head
while v != None:
yield v
v = v.next
return StopIteration
yield
가 있는 함수를 generator라고 함__iterator__
를 호출yield
== return
➡️ v가 x로 return 되어서 print(x)가 가능해짐node.next = 자기자신
, node.prev = 자기자신
head node.prev = tail
, tail.next = head
로 둔다class Node:
def __init__(self, key=None):
self.key = key
self.next = self
self.prev = self
class DoublyLinkedList:
def __init__(self):
self.head = Node() # dummy node 하나를 만들고 그것을 가르킴 (Key=None)
self.size = 0
# def __iter__():
# def __str__():
# def__len__():
def splice(self, a, b, x): # 3개 노드 a, b, x
ap = a.prev
bn = b.next
xn = x.next
ap.next = bn # cut한 뒤
bn.prev = ap # cut한 뒤
x.next = a
a.prev = x
b.next = xn
xn.prev = b
moveAfter(a, x)
: 노드 a를 노드 x 다음으로 이동
splice(a, a, x)
moveBefore(a, x)
: 노드 a를 노드 x 이전으로 이동
splice(a, a, x.prev)
insertAfter(x, key)
moveAfter(Node(key), x)
insertBefore(x, key)
moveBefore(Node(key), x)
pushFront(Key)
insertAfter(self.head, key)
pushBack(Key)
꼬리물기 느낌 ..!
def search(self, key):
v = self.head # dummy node
while v.next != self.head:
if v.key == key:
return v
v = v.next
return None
def remove(x): # 노드 x를 삭제
if x == None or x == self.head:
return
x.prev.next = x.next
x.next.prev = x.prev
key = x
del x
return key
popFront
, popBack
: remove() 사용remove(search(5))
n개 노드를 갖는 이중(양방향) 연결 리스트라고 가정
search(key)
:
splice(a,b,x)
: 6개 링크 수정,
moveAfter
, moveBefore
, insertAfter
, insertBefore
, pushFront
, pushBack
모두 splice()를 이용하므로 동일하게 remove(x)
: x 기준으로 이전, 다음 노드의 링크만 수정하면 되므로
popFront
, popBack
모두 remove()를 이용하므로 동일하게 search()
를 불러서 그 노드를 찾아야하므로 여기서 시간이 오래걸림popBack
, pushBack
같은 함수는 시간이 걸렸음