읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 사용해보면서 배운 점을 정리한 글입니다.

정의

Algorithm_Doubly_Linked_List_01

단일 연결리스트 노드에서 이전 노드 참조값이 추가되었고 구조적 차이점으로 head 외에 tail도 있어 역방향 탐색이 절반만큼 유리해졌다고 보면 된다. 단일 연결리스트의 내용은 단일 연결리스트 - Singly Linked List를 참고하자.

시간복잡도

Algorithm_Doubly_Linked_List_02

이중 연결리스트(Doubly Linked List) 구현

Node 정의

class ListNode(object):
def __init__(self, val, prev=None, next=None):
self.val = val
self.prev = prev
self.next = next

Doubly Linked List 정의

class DoublyLinkedList(object):
def __init__(self):
self.head = ListNode(None)
self.tail = ListNode(None, self.head)
self.head.next = self.tail
self.size = 0

Doubly Linked List 사이즈 반환

def size(self):
return self.size

Doubly Linked List 원소 조회

def get_node(self, idx):
if self.size == 0: # 비어있으면 None
return
elif idx > self.size:
print("ERROR: Out of Range") # 범위 초과 시 에러출력
return
else:
if idx <= self.size // 2: # 절반보다 앞이면
target = self.head # 앞에서부터 탐색
for _ in range(idx):
target = target.next
return target
else: # 절반보다 뒤쪽이면
target = self.tail # 뒤에서부터 탐색
for _ in range(self.size - idx):
target = target.prev
return target

Doubly Linked List 원소 우측 삽입

def append(self, val):
if self.size == 0: # 비어있으면 head 채움
self.head = ListNode(val, None, self.tail)
self.tail.prev = self.head
else: # head가 존재하면 뒤쪽 삽입
tmp = self.tail.prev
tmp.next = ListNode(val, tmp, self.tail)
self.tail.prev = tmp.next
self.size += 1

Doubly Linked List 원소 좌측 삽입

def appendleft(self, val):
if self.size == 0:
self.head = ListNode(val, None, self.tail)
self.tail.prev = self.head
else:
tmp = self.head
self.head = ListNode(val, None, tmp)
tmp.prev = self.head
self.size += 1

Doubly Linked List 좌표 기반 원소 삽입

def insert(self, val, idx):
if self.size == 0: # 비어있으면 좌측 삽입
self.appendleft(val)
else: # 원소가 존재 시
target = self.get_node(idx) # idx 좌표 노드 조회
if target == None: # None이면 - 범위초과
target.append(val) # 우측 삽입
elif target == self.head: # 0으로 head라면
target.appendleft(val) # 좌측 삽입
else: # 그 외
target_prev = target.prev # idx-1좌표 노드 조회
# 새로운 노드는 기존 i-1, i번 좌표 사이에 위치함
new_node = ListNode(val, target_prev, target)
# 이후 기존 노드 참조값 수정
target_prev.next, target.prev = new_node, new_node
self.size += 1

Doubly Linked List 원소 우측 삭제

def pop(self):
if self.size == 0:
print("ERROR: Already Empty Linked List")
return
else:
target = self.tail.prev
if target == self.head: # 만약 head만 있으면 초기화
self.head = ListNode(None, None, self,tail)
self.tail.prev = self.head
else: # 그 외에
# 마지막 노드 양 옆의 참조 값 수정
target.prev.next, self.tail.prev = self.tail, target.prev
self.size -= 1
return target

Doubly Linked List 좌표 기반 원소 삭제

def delete(self, idx):
if self.size == 0:
print("ERROR: Already Empty Linked List")
elif idx >= self.size:
print("ERROR: Out of Range")
else:
target = self.get_node(idx) # 제거할 노드 조회
if target == self.head: # 만약 head면 head 처리
self.head = self.head.next
self.head.prev = None
else: # 그외엔 참조값 수정
target.prev.next, target.next.prev = target.next, target.prev
self.size -= 1
del(target) # 메모리에서 제거

Doubly Linked List 원소 출력

def print(self):
target = self.head # 0번 노드부터 시작
while target != self.tail: # 현재 노드가 tail이 아닐 때까지 반복
if target.next != self.tail: # 다음 노드가 tail이 아니면
print(f'{target.val} <=> ', end='') # 값, 화살표 출력
else: # 다음 노드가 tail이면 이후 값 없으므로 값만 출력
print(target.val)
target = target.next # 다음 노드 탐색

실습 결과

foo = DoublyLinkedList()
foo.append(1)
print(foo.get_node(0).val)
foo.append(3)
foo.print()
foo.appendleft(0)
foo.print()
foo.insert(2, 2)
foo.print()
foo.append(4)
print(foo.pop().val)
foo.print()
foo.delete(1)
foo.print()

Algorithm_Doubly_Linked_List_03

'Algorithms > Data Structure' 카테고리의 다른 글

이진탐색트리(Binary Search Tree, BST)  (0) 2021.06.28
트리, 이진트리(Tree, Binray Tree)  (0) 2021.06.27
그래프(Graph)  (0) 2021.06.02
해시 테이블(Hash Table)  (0) 2021.05.30
단일 연결리스트 - Singly Linked List  (0) 2021.05.12

+ Recent posts