장점
1. 임의의 액세스가 용이함 (arr[0], arr[4] 등으로 특정 요소에 O(1)의 시간복잡도로 접근 가능)
단점
1. 삽입과 삭제 연산할때, 메모리의 위치가 연속적이고 고정적이기 때문에 많은 시간을 소모한다.
장점
1. 삽입/삭제 용이
-> 배열에서는 삽입과 삭제를 할때, 공간을 먼저 만들고 기존의 요소를 이동시켜야 한다.
단점
1. 임의로 액세스를 허용할 수 없음. 항상 첫번째 노드부터 순차적으로 요소에 액세스해야함 (이진 검색 수행 불가능) -> 배열은 인덱스로 접근 가능
2. 포인터를 기록할 메모리 공간이 각 요소마다 필요하다.
reference : https://www.freecodecamp.org/news/implementing-a-linked-list-in-javascript/
이런 구조의 LinkedList를 JavaScript로 구현해보자
const list = {
head: {
data: 6
next: {
data: 10
next: {
data: 12
next: {
data: 3
next: null
}
}
}
}
}
};
이런 형태로 표현할 수 있다. 각각의 데이터가 데이터로 저장되고, 그 다음 연결되는 것을 next에 할당해주면 된다. (가리키는 포인터가 없을 경우 null => 초기값은 null)
class ListNode {
constructor(data, next = null) {
this.data = data
this.next = next
}
}
이런 생성자 함수를 만들 수 있다.
이 생성자 함수를 통해, 위의 Linked List를 구현해보면
let node1 = new ListNode(6)
let node2 = new ListNode(10)
let node3 = new ListNode(12)
let node4 = new ListNode(3)
node1.next = node2
node2.next = node3
node3.next = node4
결과 :
각 노드간의 연결은 구현이 되었으나, 출발점이 어디서 부터 시작되는 Linked list인지는 알 수가 없다. 따라서, 새로운 생성자 함수를 만들어주자.
node1을 첫번째 요소로 가지는 List를 만들기 위해, 새로운 class를 만들어주자
class LinkedList {
constructor(head = null) {
this.head = head
}
}
let list = new LinkedList(node1)
비로소, node1에서 출발하는 Linked List가 완성되었다.
console.log(list.head.next.next.data)
// 12
이제 이 List에 사용할 수 있는 method들을 추가해보자
class LinkedList {
constructor(head = null) {
this.head = head
}
size() {
let count = 0;
let node = this.head;
while (node) {
count++;
node = node.next
}
return count;
}
clear() {
this.head = null
}
getLast() {
let lastNode = this.head;
if (lastNode) {
while (lastNode.next) {
lastNode = lastNode.next
}
}
return lastNode
}
getFirst() {
return this.head;
}
}
let newList = new LinkedList(node1)
newList.size() // 4
newList.getFirst().data // 6
newList.getLast().data // 3
newList.getLast().next // null
newList.clear() // newList.head === null