JS實現單向鏈表、雙向鏈表、循環鏈表


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 
單鏈表有一個變種 - 循環鏈表,最后一個元素指向下一個元素的指針,不是引用null,而是指向第一個元素,只需要修改下最后的next指向為head即可。
 
雙向鏈表與單鏈表的區別在於,在單鏈表中,一個節點只有鏈向下一個節點的鏈接,而在雙向鏈表中,鏈接是雙向的:一個鏈向下一個元素,另一個鏈向前一個元素。
  雙向鏈表提供了兩種迭代列表的方法:從頭到尾,或則反過來。在單鏈表中,如果我們在迭代列表中錯過了要找的元素,就需要回到列表的起點,重新開始迭代,這是雙向列表的優點。
  雙向鏈表與單向鏈表的實現類似,需要同時控制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


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM