
연결 리스트는 일련의 원소를 배열처럼 차례대로 저장하지만, 원소들이 메모리상에 연속적으로 위치하지 않는다는 점이 다르다.
연결 리스트에서 각 원소는 원소 자신과 다음 원소를 가리키는 포인터가 포함된 노드로 구성된다.

위 그림에서 보이듯이 '데이터를 저장할 장소'와 '다른 변수를 가리키기 위한 장소'가 구분되어있다.
그래서 둘 이상의 Node가 연결된 상황은 이와 같다.

class Node {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.tail = null;
this._size = 0;
}
// 주어진 값을 연결 리스트의 끝에 추가
addToTail(value) {
// 해당 함수가 실행 될 때마다 value값을 가지는 Node의 인스턴스 생성
let node = new Node(value);
// 최초 데이터를 생성 할 경우
if(!this.head) {
this.head = node;
this.tail = node;
this._size++;
// 데이터가 1개 이상 존재할 경우
} else {
this.tail.next = node;
this.tail = node;
this._size++;
}
}
// 주어진 값을 찾아서 연결을 삭제
// 찾은 후 링크를 다시 연결
remove(value) {
// 값이 없을 경우
if(!this.head) {
return undefined;
}
// 삭제할 value가 head일 경우
if(this.head.value === value) {
this.head = this.head.next;
this._size--;
}
let previousNode = this.head;
let currentNode = this.head.next;
while(currentNode) {
if(currentNode.value === value) {
previousNode.next = currentNode.next;
this._size--;
break;
} else {
previousNode = currentNode;
currentNode = currentNode.next;
}
}
}
// 주어진 인덱스의 노드를 찾아서 반환
// 값이 아니라 노드를 반환해야함
// 해당 인텍스에 노드가 없다면 undefined 반환
getNodeAt(index) {
let currentNode = this.head;
if(this._size < index) {
return undefined;
} else {
for(let i = 0; i < this._size; i++) {
if(i === index) {
return currentNode;
}
currentNode = currentNode.next;
}
}
}
// 연결리스트에 주어진 값을 가지는 노드의 존재 여부 반환
contains(value) {
let currentNode = this.head;
while(currentNode) {
if(currentNode.value === value) {
return true;
}
currentNode =currentNode.next;
}
return false;
}
// 주어진 값의 인덱스 반환, 없을 경우 -1 반환
indexOf(value) {
let count = 0;
// 현재 인스턴스의 head
let currentNode = this.head;
// 현재 인스턴스 부터 next에 저장되어 있는 node를
// 모두 순회하면서 각 node의 value값이 파라미터와 같은지 확인
while(currentNode) {
if(currentNode.value === value) {
return count;
}
count++;
currentNode = currentNode.next;
}
return -1;
}
size() {
return this._size;
}
}