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

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

이중 연결리스트(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: |
| 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: |
| self.head = ListNode(val, None, self.tail) |
| self.tail.prev = self.head |
| else: |
| 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) |
| if target == None: |
| target.append(val) |
| elif target == self.head: |
| target.appendleft(val) |
| else: |
| target_prev = target.prev |
| |
| 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: |
| 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: |
| 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 |
| while target != self.tail: |
| if target.next != self.tail: |
| print(f'{target.val} <=> ', end='') |
| else: |
| 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() |
