연결리스트(Linked List)는 노드(Node)의 연결로 이루어진 자료구조이다. 연결리스트는 데이터의 추가와 삭제에 대해 O(n)(선형 시간)의 시간 복잡도를 갖는 배열과 달리, O(1)(상수 시간)의 시간 복잡도를 갖는다. 다만 추가와 삭제 속도가 더 빠른 대신, 연결리스트의 각 노드는 인덱스를 갖지 않는다. 따라서 연결리스트에서 어떤 특정 데이터를 검색하고자 할 경우, 처음부터 전체 연결리스트를 훑어야하는 O(n)(선형 시간)의 복잡도를 필요로 한다.
노드(Node)는 Head(첫번째 노드)와 Tail(마지막 노드)로 구성되어 있으며, 각 노드는 다음 노드를 가리키는 포인터(Next)를 가지고 있다.
이미지 출처: codestates urclass
연결리스트에는 단일 연결리스트(Singly-Linked List)와 이중 연결리스트(Doubly-Linked List) 등의 종류가 있다.
이미지 출처: 필자 제작
이미지 출처: 필자 제작
class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this._size = 0;
}
//주어진 값을 연결 리스트의 끝에 추가
addToTail(value) {
let node = new Node(value);
//리스트가 없는 경우, head와 tail 생성
if(this.head === null){
this.head = node;
this.tail = node;
//리스트가 있는 경우, tail을 추가하고 포인터 설정
}else{
this.tail.next = node;
this.tail = node;
}
this._size++;
return this;
}
//주어진 값을 찾아서 연결을 해제(삭제)
remove(value) {
if(this.head === null){
return undefined;
} else if(value === this.head.value){
this.head = this.head.next;
}
this._size--;
return this;
}
//주어진 인덱스의 노드를 찾아서 반환
getNodeAt(index) {
let list = this.head;
if(index > this._size){
return undefined;
} else {
for(let i = 0; i < index; i++){
list = list.next;
}
}
return list;
}
//연결리스트에 주어진 값을 가지는 노드의 존재 여부를 반환
contains(value) {
let list = this.head;
while(list){
if(value === list.value){
return true;
} else {
list = list.next;
}
}
return false;
}
//주어진 값의 인덱스를 반환, 없을 경우 -1을 반환
indexOf(value) {
let list = this.head;
let count = 0;
while(list){
if(value === list.value){
return count;
}else{
list = list.next;
count++
}
}
return -1;
}
size() {
return this._size;
}
}