https://cloud.tencent.com/developer/article/1114246
鏈表存儲有序的元素的集合,但是和數組不同的是,鏈表中的元素在內存中的存儲並不是連續的。每一個鏈表元素都包含了一個存儲元素本身的節點和一個指向下一個元素的引用。看起來就像這樣:
相對於傳統的數組,鏈表的一個好處就是增刪的時候無需移動其它元素,只要更改指針的指向就可以了。但是缺點就是如果想要訪問鏈表中的元素,需要從頭開始循環迭代到你想要的元素。
function LinkedList() {
// Node輔助類,表示要加入列表的項,element是即將添加到列表的值,next是指向列表中下一個節點項的指針
let Node = function (element) {
this.element = element
this.next = null
}
let length = 0
let head = null
// 向鏈表尾部追加元素
this.append = function (element) {
let node = new Node(element)
let current
if (head === null) { // 列表中第一個節點
head = node
} else {
current = head
while (current.next) {
current = current.next // 找到最後一項,是null
}
current.next = node // 給最後一項賦值
}
length++ // 更新列表的長度
}
// 從鏈表中移除指定位置元素
this.removeAt = function (position) {
if (position > -1 && position < length) { // 值沒有越界
let current = head
let previous, index = 0
if (position === 0) { // 移除第一項
head = current.next
} else {
while (index++ < position) {
previous = current
current = current.next
}
previous.next = current.next // 將previous與current的下一項連接起來,跳過current,從而移除
}
length-- // 更新列表的長度
return current.element
} else {
return null
}
}
// 在鏈表任意位置插入一個元素
this.insert = function (position, element) {
if (position >= 0 && position <= length) { // 檢查越界值
let node = new Node(element),
current = head,
previous,
index = 0
if (position === 0) { // 在第一個位置添加
node.next = current
head = node
} else {
while (index++ < position) {
previous = current
current = current.next
}
node.next = current // 在previous與current的下一項之間插入node
previous.next = node
}
length++
return true
} else {
return false
}
}
// 把鏈表內的值轉換成一個字符串
this.toString = function () {
let current = head,
string = ''
while (current) {
string += current.element + ' '
current = current.next
}
return string
}
// 在鏈表中查找元素並返回索引值
this.indexOf = function (element) {
let current = head,
index = 0
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
}
// 從鏈表中移除指定元素
this.remove = function (element) {
let index = this.indexOf(element)
return this.removeAt(index)
}
this.isEmpty = function () {
return length === 0
}
this.size = function () {
return length
}
this.getHead = function () {
return head
}
}
let list = new LinkedList()
list.append(1)
list.append(2)
console.log(list.toString()) // 1 2
list.insert(0, 'hello')
list.insert(1, 'world')
console.log(list.toString()) // hello world 1 2
list.remove(1)
list.remove(2)
console.log(list.toString()) // hello world
雙向鏈表提供了兩種迭代列表的方法:從頭到尾,或則反過來。在單鏈表中,如果我們在迭代列表中錯過了要找的元素,就需要回到列表的起點,重新開始迭代,這是雙向列表的優點。
雙向鏈表與單向鏈表的實現類似,需要同時控制next、prev兩個指針,同時需要增加尾引用tail。
function DoubleLinkedList() {
// Node輔助類,表示要加入列表的項,element是即將添加到列表的值,next是指向列表中下一個節點項的指針
let Node = function (element) {
this.element = element
this.prev = null // 新增一個向前的指針
this.next = null
}
let length = 0
let head = null
let tail = null // 新增一個尾引用
// 向鏈表尾部追加元素
this.append = function (element) {
let node = new Node(element)
let current
if (head === null) { // 列表中第一個節點
head = node // head與tail是同一個元素
tail = node
} else {
current = head
while (current.next) {
current = current.next // 找到最後一項,是null
}
current.next = node // 給最後一項賦值
node.prev = current
tail = node // 修改尾引用
}
length++ // 更新列表的長度
}
// 從鏈表中移除指定位置元素
this.removeAt = function (position) {
if (position > -1 && position < length) { // 值沒有越界
let current = head
let previous,
index = 0
if (position === 0) { // 移除第一項
head = current.next
if (length === 1) { // 只有一項
tail = null
} else {
head.prev = null
}
} else if (position === length - 1) { // 移除最後一項
current = tail
tail = current.prev
tail.next = null
}
else {
while (index++ < position) {
previous = current
current = current.next
}
previous.next = current.next // 將previous與current的下一項連接起來,跳過current,從而移除
current.next.prev = previous
}
length-- // 更新列表的長度
return current.element
} else {
return null
}
}
// 在鏈表任意位置插入一個元素
this.insert = function (position, element) {
if (position >= 0 && position <= length) { // 檢查越界值
let node = new Node(element),
current = head,
previous,
index = 0
if (position === 0) { // 在第一個位置添加
if (!head) {
head = node
tail = node
}else {
node.next = current
current.prev = node
head = node
}
node.next = current
head = node
} else if (position === length) {
current = tail
current.next = node
node.prev = current
tail = node
} else {
while (index++ < position) {
previous = current
current = current.next
}
node.next = current // 在previous與current的下一項之間插入node
previous.next = node
current.prev = node
node.prev = previous
}
length++
return true
} else {
return false
}
}
// 把鏈表內的值轉換成一個字符串
this.toString = function () {
let current = head,
string = ''
while (current) {
string += current.element + ' '
current = current.next
}
return string
}
// 在鏈表中查找元素並返回索引值
this.indexOf = function (element) {
let current = head,
index = 0
while (current) {
if (element === current.element) {
return index
}
index++
current = current.next
}
return -1
}
// 從鏈表中移除指定元素
this.remove = function (element) {
let index = this.indexOf(element)
return this.removeAt(index)
}
this.isEmpty = function () {
return length === 0
}
this.size = function () {
return length
}
this.getHead = function () {
return head
}
}
let list = new DoubleLinkedList()
list.append(1)
list.append(2)
console.log(list.toString()) // 1 2
list.insert(0, 'hello')
list.insert(1, 'world')
console.log(list.toString()) // hello world 1 2
list.remove(1)
list.remove(2)
console.log(list.toString()) // hello world
轉載於:https://www.cnblogs.com/leftJS/p/11074346.html