Javascript/DSA
LinkedList Data Structure
미스터황탄
2016. 8. 9. 15:32
About LinkedList
자바스크립트에서 리스트는 배열로 구현한다.
다른 언어에서 배열은 길이가 정해져 있어 배열에 저장하는 데이터가
가변적이라면 메모리에 낭비 또는 초과를 일으킨다.
이러한 문제를 개선하기위해 LinkedList 를 사용 할수있다.
기차의 형태를 연상하면 이해하기 쉬우며 추가,삭제가 용이 하지만
특정 요소 접근이나 검색은 비효율적이다.
LinkedList 는 Node 라는 객체의 집합인데 각 객체간 연결이 되어 있는
방식이기때문에 요소를 참조할뿐 인덱스를 부여받는것이 아니기 때문이다.
let arr = ["hello","world","javascript"];
let head = { element: "head" , next: Node1 }
let Node1 = { element: "hello", next: Node2 }
let Node2 = { element: "world", next: Node3 }
let Node3 = { element: "javascript", next: null }
arr 은 배열 이다 world
에 접근하기위해선 배열생성시 부여된 인덱스 번호만 알고 있으면 된다. arr[1]
Node1 ~ Node3 은 LinkedList 를 표현하기 위해 임의로 정의한 객체 이다
world
에 접근하기 위해선 head로 부터 element 값이 world
인 객체를 next로 참조 해서 찾아가야 한다.
More About
일반적인 링크드 리스트는 단방향 으로 구현 되며 기준이되는 head 로 시작해서 null 로 끝나게 된다.
이를 개선하기 위해 양방향 리스트 를 사용 할수 있는데 양방향 리스트는 Node에 previous 를 추가하여 코드를 개선 시킨다.
양방향 리스트는 코드가 복잡해 질수 있는 단점이 있는데 상황에 따라 순환 구조인 순환형 리스트 를 사용할수 있다.
순환형 리스트는 단방향 리스트의 끝인 null 포인트를 시작점인 head로 지정하여 순환형태를 만든다.
ADT (Abstract Data Type)
methodname | contents |
---|---|
append(element) | 노드의 끝에 새로운 노드를 추가한다 |
insert(position, element) | 원하는 위치에 새로운 노드를 추가한다 |
remove(element) | 노드를 삭제 한다. |
핵심 메소드만 설명 하였습니다.
implementation
//ES6
class Node {
constructor(el) {
this.element = el
this.next = null
this.prev = null //doubly new
}
}
class LinkedList {
constructor() {
this.length = 0
this.head = null
this.tail = null //doubly new
}
append(element) {
let node = new Node(element),
current = null
if (this.head == null) {
this.head = node
} else {
current = this.head
while (current.next) {
current = current.next
}
current.next = node
}
this.length++
}
remove(element) {
var index = this.indexOf(element)
return this.removeAt(index)
}
removeAt(position) {
if (position > -1 && position < this.length) {
let current = this.head,
previous,
index = 0
if (position === 0) {
this.head = current.next
if (this.length === 1) { //doubly new
this.tail = null
} else {
this.head.prev = null
}
} else if (position === length-1) {
current = this.tail
this.tail = current.prev
this.tail.next = null
} else {
while (index++ < position) {
previous = current
current = current.next
}
previous.next = current.next
current.next.prev = previous
}
length--
return current.element
} else {
return null
}
}
insert(position, element) {
if (position >= 0 && position <= this.length) {
var node = new Node(element),
current = this.head,
previous,
index = 0
if(position === 0) {
if (!this.head) { //doubly new
this.head = node
this.tail = node
} else {
node.next = current
current.prev = node
this.head = node
}
} else if (position === this.length) { //doubly new
current = this.tail
current.next = node
node.prev = current
this.tail = node
} else {
while (index++ < position) {
previous = current
current = current.next
}
node.next = current
previous.next = node
current.prev = node //doubly new
node.prev = previous //doubly new
}
length++
return true
} else {
return false
}
}
toString() {
var current = this.head,
string = ''
while (current) {
string = current.element
current = current.next
}
return string
}
indexOf(element) {
var current = this.head,
index = -1
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
}
isEmpty() {
return this.length === 0
}
size() {
return this.length
}
getHead() {
return this.head
}
advance(n) {
for (;;) {
if (n <= 0) break
this.head = this.head.next
n--
}
}
back(n) {
for (;;) {
if (n <= 0) break
this.head = this.head.prev
n--
}
}
show() {
return this.head.element
}
}