List
- 인덱스가 없음
- 노드와 다음을 가리키는 포인터로 연결된다.
- 무작위 접근이 불가 (index가 없기 때문)
- 삽입과 삭제가 쉽다.
Array
- 인덱스가 있음
- 삽입, 삭제는 소모되는 비용이 크다
- 특정 인덱스에서 빠르게 접근할 수 있다.
class Node {
constructor(val){
this.val = val;
this.next = null;
}
}
class SinglyLinkedList{
constructor(){
this.head = null;
this.tail = null;
this.length=0;
}
}
큰 틀은 위와 같다.
push 메소드
push(val){
const node = new Node(val);
if(this.length ===0 ){ // if(!this.head)
this.head = node;
this.tail = node;
}
else{
this.tail.next = node;
this.tail = node;
}
this.length++;
}
pop 메소드
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--;
if(this.length === 0){
this.head = null;
this.tail = null;
}
return current.val;
}
역방향 포인터를 가지고 있지 않기 때문에 처음부터 리스트를 따라가야한다.
shift 메소드 (맨 앞 노드 제거)
현재 헤드가 가리키고 있는 노드를 제거한 후 헤드가 가리키고 있던 리스트의 다음 노드를 가리키도록 한다.
shift(){
if(!this.head) return undefined;
let currentHead = this.head;
this.head = currentHead.next;
this.length--;
if(this.length===0) this.tail = null;
return currentHead.val;
}
unshift 메소드 ( 맨 앞에 노드를 추가 )
unshift(val){
const newNode = new Node(val);
newNode.next = this.head;
this.head = newNode;
this.length++;
if(this.length===1) this.tail = newNode;
}
get 메소드 ( index 위치의 노드 반환)
get(idx){
if(idx<0 || idx>=this.length) return null;
let cnt = 0;
let current = this.head;
while(cnt!==idx){
current = current.next;
cnt ++;
}
return current;
}
set 메소드( index 위치의 노드 값 변경)
set(idx,val){
let foundNode = this.get(idx);
if(foundNode){
foundNode.val = val;
return true;
}
return false;
}
이미 구현된 get 메서드를 통해서 index위치의 노드를 가져온다.
그 노드의 값을 변경한다.
set 유무에 따른 true, false 반환
insert 메소드 ( index 위치에 추가 )
내풀이
push나 unshift 와 같은 것들을 활용하면 되었는데 생각을 못했다,,
```jsx
insert(idx,val){
const newNode = new Node(val);
let foundNode = this.get(idx-1);
if(foundNode){
newNode.next = foundNode.next;
foundNode.next = newNode;
if(idx===this.length) this.tail = newNode;
this.length++;
return true;
}
else{ //
newNode.next = this.head;
this.head = newNode;
this.length++;
return true;
}
return false;
}
```
insert(idx,val){
if(idx<0 || idx>this.legnth) return false;
if(idx === this.length ) return this.push(val); //맨마지막에 추가
if(idx === 0) return this.unshift(val);
let newNode = new Node(val);
let prev = this.get(idx-1);
let temp = prev.next;
prev.next = newNode;
newNode.next = temp ;
this.length++;
return true;
}
인덱스가 음수이거나, 길이보다 클 경우 false반환
인덱스가 리스트의 길이랑 같으면 맨 마지막에 추가하는 push 메서드 이용
인덱스가 0 (처음)이면 맨 처음에 추가하는 unshift 메서드 이용
중간에 값을 추가할 경우, 이전 노드를 받아온다.
이전 노드가 가리키는 값을 temp 에 저장하고, 이전 노드가 새로운 노드를 가리키게하고, 새로운 노드는temp 를 가리킨다.
추가했기때문에 길이 1 증가
성공 시 true, 실패 시 false 반환
remove 메소드
remove(idx){
if(idx<0 || idx>=this.legnth) return undefined;
if(idx === this.length ) return this.pop(); //맨마지막에 제거
if(idx === 0) return this.shift(); // 맨 처음 제거
let prev = this.get(idx-1);
let removeNode = prev.next;
prev.next = removeNode.next;
this.length--;
return removeNode;
}
인덱스가 음수이거나, 길이보다 크거나 같을 경우 false반환
인덱스가 리스트의 길이랑 같으면 맨 마지막에 삭제하는 pop 메서드 이용
인덱스가 0 (처음)이면 맨 처음에 삭제하는 shift 메서드 이용
중간 인덱스에 값을 삭제할 경우, 이전 노드를 받아온다.
이전 노드가 가리키는것을 제거할 노드가 아닌 제거할 노드가 가리키는 것을 지정해주어 제거할 노드와의 연결을 끊는다.
길이를 1개 감소시키고 삭제된 노드를 반환한다. 실패 시 undefined 반환
reverse 메소드
0부터 채워넣어야하는데 마지막 요소부터 거꾸로 접근이 안됨.
주어진 연결 리스트의 노드순서가 역으로 연결되도록 해야한다.
리스트를 따라가면서 순서를 계속 역으로 바꿔나감
reverse(){
let currentNode = this.head;
[this.head,this.tail] = [this.tail,this.head];
let beforeNode = null
let nextNode;
while(true){
nextNode = currentNode.next;
currentNode.next=beforeNode;
beforeNode = currentNode;
currentNode = nextNode;
if(!currentNode) break;
}
}