The only thing special about get is that because you can traverse forwards or backwards, you can conditionally traverse in either direction depending on if the index is closer to the left or closer to the right. This is a slight optimization that makes getO(n / 2).
get(index) {
if (index < 0 || index >= this.length) return undefined
const middle = Math.floor(this.length / 2)
if (index <= middle) {
let counter = 0
let targetNode = this.head
while (counter < index) {
targetNode = targetNode.next
counter++
}
return targetNode
} else {
let counter = this.length - 1
let targetNode = this.tail
while (counter > index) {
targetNode = targetNode.prev
counter--
}
return targetNode
}
}
Set
set(index, val) {
const targetNode = this.get(index)
if (!targetNode) return false
targetNode.val = val
return true
}
Insert
With insert, the only special thing you're doing is connecting nodes at both ends (prev and next).
insert(index, val) {
if (index < 0 || index > this.length) return false
if (index === this.length) {
this.push(val)
} else if (index === 0) {
this.unshift(val)
} else {
const newNode = new Node(val)
const beforeNode = this.get(index - 1)
const afterNode = beforeNode.next
// Connect previous node with new node
beforeNode.next = newNode
newNode.prev = beforeNode
// Connect new node with old node
newNode.next = afterNode
afterNode.prev = newNode
this.length++
}
return true
}
Remove
Just like insert, remove requires connecting the severed ends of each surrounding node.