A data structure that contains a head, tail and length property.
Linked Lists consist of nodes, and each node has a value and a pointer to another node or null.
Array : 엘레베이터가 있는 빌딩 ( 5층으로 가주세요 → 한번에 가능)
Singly Linked List : 엘레베이터가 없는 빌딩 ( 계단을 통해 한층한층 옮겨다님 )
Linked List 는 Data 의 삽입(insertion)과 삭제(deletion)에 용이하다
Array가 추가와 삭제에 대해 O(n) , linear 복잡도를 갖는 반면, Linked List 는 O(1), constant 시간 복잡도를 갖는다.
단 , 특정 데이터를 연결리스트에서 검색하고자 할 경우, 처음부터 전체 리스트를 훑어야 하며, 이는 O(n) (linear complexity) 의 복잡도를 필요로 합니다.
keyword : 자료의 추가, 삭제를 용이하게 하기 위함.
자원의 사용량 측면에서는 array가 더 효율적임 (linked list는 next 포인터까지 주어져야하므로 ..)
기본세팅
class Node {
constructor(val) {
this.val = val;
this.next = null;
}
}
class SinglyLinkedList {
constructor() {
this.length = 0;
this.head = null;
this.tail = null;
}
Pushing pseudocode
push(val){
const newNode = new Node(val);
if (!this.head) {
this.head = newNode;
this.tail = this.head;
} else {
this.tail.next = newNode;
this.tail = newNode;
}
this.length += 1;
return this;
}
Popping pseudocode
pop(){
if (!this.head) {
return undefined;
}
let current = this.head;
let newTail = current;
while(current.next) {
newTail = current;
current = current.next;
}
this.tail = newTail;
this.tail.next = null;
this.length -= 1;
if(this.length === 0) {
this.head = null;
this.tail = null;
}
return current;
}
Shifting pseudocode
shift(){
if (!this.head) {
return undefined;
}
let currentHead = this.head;
this.head = currentHead.next;
this.length -= 1;
if(this.length === 0){
this.tail = null;
}
return currentHead;
}
Unshifting pseudocode
unshift(val){
let newNode = new Node(val)
if(!this.head) {
this.head = newNode;
this.tail = this.head;
} else {
newNode.next = this.head;
this.head = newNode;
}
this.length++;
return this;
}
Retrieving a node by it's position in the Linked List!
Get pseudocode
get(index){
if(index < 0 || index >= this.length) return null;
let counter = 0;
let current = this.head;
while (counter !== index) {
current = current.next;
counter++;
}
return current;
}
Changing the value of a node based on it's position in the Linked List
Set pseudocode
set(index, value){
let foundNode = this.get(index);
if(foundNode) {
foundNode.val = value;
return true;
}
return false;
}
Adding a node to the Linked List at a specific position
Insert pseudocode
insert(index, value) {
if(index < 0 || index > this.length) {
return false;
}
if (index === this.length) {
return !!this.push(value);
}
if (index === 0) {
return !!this.unshift(value);
}
let newNode = new Node(value);
let prev = this.get(index -1);
let temp = prev.next;
prev.next = newNode;
newNode.next = temp;
this.length++;
return true;
}
Removing a node from the Linked List at a specific position
Remove pseudocode
remove(index){
if(index < 0 || index > this.length) {
return undefined
}
if (index === this.length-1 ) {
return this.pop();
}
if (index === 0) {
return this.shift();
}
let previousNode = this.get(index-1);
let removed = previousNode.next;
previousNode.next = removed.next;
this.length--;
return removed;
}
Reversing the Linked List in place!
Reverse pseudocode
reverse() {
let node = this.head;
this.head = this.tail;
this.tail = node;
let next;
let prev = null;
for (let i=0; i<this.length; i++) {
next = node.next;
node.next = prev;
prev = node;
node = next;
}
return this;
}
Insertion - O(1)
Removal = It depends.. O(1) or O(n)
Searching - O(n)
Access - O(n)