seunghyun Note
Doubly Linked List with JS 본문
단일 연결 리스트이중 연결 리스트- 스택 & 큐 (배열로 하는 방법은 숙지했음! linked list로 구현해 보기)
- 이진 검색 트리
- 트리 순회
- 이진 힙
- 해시 테이블 (사용해 봤지만 복습)
- 그래프, 그래프 순회
- 다익스트라 알고리즘
- 동적 프로그래밍
이중 연결리스트를 왜 사용하는지 몰랐는데.. 최근에 풀었던 덱 문제를 풀면서 시간복잡도가 커짐을 느끼고 이중 연결리스트를 사용해서 문제를 해결했던 기억이 있다.
이중 연결리스트는 일반 연결리스트와 달리 prev, next가 생긴 것이다. 조금 더 복잡해졌지만 그만큼 효율이 좋은 거 같다.
Class Setting
기본 세팅은 Linked List와 비슷하지만 추가되는 것이 있다.
class Node{
constructor(val){
this.val = val;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList{
constructor(){
this.head = null;
this.tail = null;
this.length = 0;
}
}
Linked List와 비슷하게 push, pop,shift, unshift를 다룰 것이다.
Push
연결리스트를 이해할 때 그림을 그리고 직관적인 표현이 필요했는데 제일 만족스러운 조직도이다.
push는 새로운 node가 들어오면
1. tail의 next를 새로운 노드에 연결
2. 새로운 노드의 prev 를 tail에 연결
3. tail을 새로운 노드로 가리킴
push(val) {
var newNode = new Node(val);
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}
this.length++;
return this;
}
항상 길이가 0일때 초기화와 push 했을 때 길이를 추가해 준다.
pop
맨 뒤의 값을 제거 하는 것이다.
1. tail을 전 노드를 가리킨다.
2. tail의 next를 null로 바꾼다.
3. 제거할 노드의 prev를 null로 해서 없앤다.
pop() {
if (!this.head) return undefined;
var poppedNode = this.tail;
if (this.length === 1) {
this.head = null;
this.tail = null;
} else {
this.tail = poppedNode.prev;
this.tail.next = null;
poppedNode.prev = null;
}
this.length--;
return poppedNode;
}
shift
맨 앞의 원소를 제거하는 것이다.
1. head를 head를 저장한 객체의 next로 연결한다.
2. 바뀐 head의 prev를 null로 바꾼다.
3. 따로 저장한 객체의 노드의 next를 null로 바꿔서 제거한다.
shift() {
if (this.length === 0) return undefined;
var oldHead = this.head;
if (this.length === 1) {
this.head = null;
this.tail = null;
} else {
this.head = oldHead.next;
this.head.prev = null;
oldHead.next = null;
}
this.length--;
return oldHead;
}
unshift
맨 앞에 원소 넣기
1. 기존 head의 prev를 새로운 Node에 연결한다.
2. 연결된 새로운 Node의 next를 아직 바꾸지 않은 head로 연결한다.
3. 연결이 됐다면 현재 head를 새로운 Node로 가리킨다.
set, get, insert는 간단해서 따로 안 다룰 예정(사실 조금 귀찮음..)
최종 코드
class Node {
constructor(val) {
this.val = val;
this.next = null;
this.prev = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
this.length = 0;
}
push(val) {
var newNode = new Node(val);
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}
this.length++;
return this;
}
pop() {
if (!this.head) return undefined;
var poppedNode = this.tail;
if (this.length === 1) {
this.head = null;
this.tail = null;
} else {
this.tail = poppedNode.prev;
this.tail.next = null;
poppedNode.prev = null;
}
this.length--;
return poppedNode;
}
shift() {
if (this.length === 0) return undefined;
var oldHead = this.head;
if (this.length === 1) {
this.head = null;
this.tail = null;
} else {
this.head = oldHead.next;
this.head.prev = null;
oldHead.next = null;
}
this.length--;
return oldHead;
}
unshift(val) {
var newNode = new Node(val);
if (this.length === 0) {
this.head = newNode;
this.tail = newNode;
} else {
this.head.prev = newNode;
newNode.next = this.head;
this.head = newNode;
}
this.length++;
return this;
}
get(index) {
if (index < 0 || index >= this.length) return null;
var count, current;
if (index <= this.length / 2) {
count = 0;
current = this.head;
while (count !== index) {
current = current.next;
count++;
}
} else {
count = this.length - 1;
current = this.tail;
while (count !== index) {
current = current.prev;
count--;
}
}
return current;
}
set(index, val) {
var foundNode = this.get(index);
if (foundNode != null) {
foundNode.val = val;
return true;
}
return false;
}
insert(index, val) {
if (index < 0 || index > this.length) return false;
if (index === 0) return !!this.unshift(val);
if (index === this.length) return !!this.push(val);
var newNode = new Node(val);
var beforeNode = this.get(index - 1);
var afterNode = beforeNode.next;
(beforeNode.next = newNode), (newNode.prev = beforeNode);
(newNode.next = afterNode), (afterNode.prev = newNode);
this.length++;
return true;
}
}
var list = new DoublyLinkedList();
list.push("Harry");
list.push("Ron");
list.push("Hermione");
console.log(list);
list.pop();
console.log(list);
참고자료
JavaScript 알고리즘 & 자료구조 마스터 클래스 :
https://www.udemy.com/course/best-javascript-data-structures
Insertion in a Doubly Linked List :
https://www.geeksforgeeks.org/introduction-and-insertion-in-a-doubly-linked-list/
Insertion in a Doubly Linked List - GeeksforGeeks
A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.
www.geeksforgeeks.org
Doubly Linked List series :
Doubly Linked List Series: Creating shift() and unshift() methods with JavaScript
Building off of last week's blog on Doubly Linked List classes, push(), and pop() methods - linked...
dev.to
'코딩테스트 > 코테를 위한 알고리즘 & 자료구조 정리' 카테고리의 다른 글
Tree traversal(1) with JS (0) | 2024.02.14 |
---|---|
BST(Binary Search Tree) with JS (0) | 2024.02.07 |
Queue with JS (1) | 2024.01.30 |
Stack with JS (0) | 2024.01.25 |
Singly Linked Lists with JS (0) | 2024.01.23 |