JavaScript數(shù)據(jù)結(jié)構(gòu)之鏈表的實(shí)現(xiàn)
前面樓主分別討論了數(shù)據(jù)結(jié)構(gòu)棧與隊(duì)列的實(shí)現(xiàn),當(dāng)時(shí)所用的數(shù)據(jù)結(jié)構(gòu)都是用的數(shù)組來(lái)進(jìn)行實(shí)現(xiàn),但是數(shù)組有的時(shí)候并不是最佳的數(shù)據(jù)結(jié)構(gòu),比如在數(shù)組中新增刪除元素的時(shí)候需要將其他元素進(jìn)行移動(dòng),而在javascript中使用spit()方法不需要訪問(wèn)其他元素。如果你在使用數(shù)組的時(shí)候發(fā)現(xiàn)很慢,就可以考慮使用鏈表。
鏈表的概念
鏈表是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)。它是動(dòng)態(tài)地進(jìn)行存儲(chǔ)分配的一種結(jié)構(gòu)。鏈表有一個(gè)“頭指針”變量,以head表示,它存放一個(gè)地址,指向一個(gè)元素。每個(gè)結(jié)點(diǎn)都使用一個(gè)對(duì)象的引用指標(biāo)它的后繼,指向另一個(gè)結(jié)點(diǎn)的引用叫做鏈。
數(shù)組元素依靠下標(biāo)(位置)來(lái)進(jìn)行引用,而鏈表元素則是靠相互之間的關(guān)系來(lái)進(jìn)行引用。因此鏈表的插入效率很高,下圖演示了鏈表結(jié)點(diǎn)d的插入過(guò)程:
刪除過(guò)程:
基于對(duì)象的鏈表
我們定義2個(gè)類(lèi),Node類(lèi)與LinkedList類(lèi),Node為結(jié)點(diǎn)數(shù)據(jù),LinkedList保存操作鏈表的方法。
首先看Node類(lèi):
function Node(element){ this.element = element; this.next = null; }
element用來(lái)保存結(jié)點(diǎn)上的數(shù)據(jù),next用來(lái)保存指向一下結(jié)點(diǎn)的的鏈接。
LinkedList類(lèi):
function LinkedList(){ this.head = new Node('head'); this.find = find; this.insert = insert; this.remove = remove; this.show = show; }
find()方法,從頭結(jié)點(diǎn)開(kāi)始,沿著鏈表結(jié)點(diǎn)一直查找,直到找到與item內(nèi)容相等的element則返回該結(jié)點(diǎn),沒(méi)找到則返回空。
function find(item){ var currentNode = this.head;//從頭結(jié)點(diǎn)開(kāi)始 while(currentNode.element!=item){ currentNode = currentNode.next; } return currentNode;//找到返回結(jié)點(diǎn)數(shù)據(jù),沒(méi)找到返回null }
Insert方法。通過(guò)前面元素插入的演示可以看出,實(shí)現(xiàn)插入簡(jiǎn)單四步:
1、創(chuàng)建結(jié)點(diǎn)
2、找到目標(biāo)結(jié)點(diǎn)
3、修改目標(biāo)結(jié)點(diǎn)的next指向鏈接
4、將目標(biāo)結(jié)點(diǎn)的next值賦值給要插入的結(jié)點(diǎn)的next
function insert(newElement,item){ var newNode = new Node(newElement); var currentNode = this.find(item); newNode.next = currentNode.next; currentNode.next = newNode; }
Remove()方法。刪除某一節(jié)點(diǎn)需要先找到被刪除結(jié)點(diǎn)的前結(jié)點(diǎn),為此我們定義方法frontNode():
function frontNode(item){ var currentNode = this.head; while(currentNode.next.element!=item&¤tNode.next!=null){ currentNode = currentNode.next; } return currentNode; }
簡(jiǎn)答三步:
1、創(chuàng)建結(jié)點(diǎn)
2、找到目標(biāo)結(jié)點(diǎn)的前結(jié)點(diǎn)
3、修改前結(jié)點(diǎn)的next指向被刪除結(jié)點(diǎn)的n后一個(gè)結(jié)點(diǎn)
function remove(item){ var frontNode = this.frontNode(item); //console.log(frontNode.element); frontNode.next = frontNode.next.next; }
Show()方法:
function show(){ var currentNode = this.head,result; while(currentNode.next!=null){ result += currentNode.next.element;//為了不顯示head結(jié)點(diǎn) currentNode = currentNode.next; } }
測(cè)試程序:
var list = new LinkedList(); list.insert("a","head"); list.insert("b","a"); list.insert("c","b"); console.log(list.show()); list.remove("b"); console.log(list.show());
輸出:
雙向鏈表
從鏈表的頭節(jié)點(diǎn)遍歷到尾節(jié)點(diǎn)很簡(jiǎn)單,但有的時(shí)候,我們需要從后向前遍。此時(shí)我們可以通過(guò)給 Node 對(duì)象增加一個(gè)屬性,該屬性存儲(chǔ)指向前驅(qū)節(jié)點(diǎn)的鏈接。樓主用下圖來(lái)雙向鏈表的工作原理。
首先我們先給Node類(lèi)增加front屬性:
function Node(element){ this.element = element; this.next = null; this.front = null; }
當(dāng)然,對(duì)應(yīng)的insert()方法和remove()方法我們也需要做相應(yīng)的修改:
function insert(newElement,item){ var newNode = new Node(newElement); var currentNode = this.find(item); newNode.next = currentNode.next; newNode.front = currentNode;//增加front指向前驅(qū)結(jié)點(diǎn) currentNode.next = newNode; } function remove(item){ var currentNode = this.find(item);//找到需要?jiǎng)h除的節(jié)點(diǎn) if (currentNode.next != null) { currentNode.front.next = currentNode.next;//讓前驅(qū)節(jié)點(diǎn)指向需要?jiǎng)h除的節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn) currentNode.next.front = currentNode.front;//讓后繼節(jié)點(diǎn)指向需要?jiǎng)h除的節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn) currentNode.next = null;//并設(shè)置前驅(qū)與后繼的指向?yàn)榭? currentNode.front = null; } }
反序顯示鏈表:
需要給雙向鏈表增加一個(gè)方法,用來(lái)查找最后的節(jié)點(diǎn)。 findLast() 方法找出了鏈表中的最后一個(gè)節(jié)點(diǎn),可以免除從前往后遍歷鏈。
function findLast() {//查找鏈表的最后一個(gè)節(jié)點(diǎn) var currentNode = this.head; while (currentNode.next != null) { currentNode = currentNode.next; } return currentNode; }
實(shí)現(xiàn)反序輸出:
function showReverse() { var currentNode = this.head, result = ""; currentNode = this.findLast(); while(currentNode.front!=null){ result += currentNode.element + " "; currentNode = currentNode.front; } return result; }
測(cè)試程序:
var list = new LinkedList(); list.insert("a","head"); list.insert("b","a"); list.insert("c","b"); console.log(list); list.remove("b"); console.log(list.show()); console.log(list.showReverse());
輸出:
循環(huán)鏈表
循環(huán)鏈表是另一種形式的鏈?zhǔn)酱尜A結(jié)構(gòu)。它的特點(diǎn)是表中最后一個(gè)結(jié)點(diǎn)的指針域指向頭結(jié)點(diǎn),整個(gè)鏈表形成一個(gè)環(huán)。循環(huán)鏈表和單向鏈表相似,節(jié)點(diǎn)類(lèi)型都是一樣的。唯一的區(qū)別是,在創(chuàng)建循環(huán)鏈表時(shí),讓其頭節(jié)點(diǎn)的 next 屬性指向它本身,即:
head.next = head
這種行為會(huì)傳導(dǎo)至鏈表中的每個(gè)節(jié)點(diǎn),使得每個(gè)節(jié)點(diǎn)的 next 屬性都指向鏈表的頭節(jié)點(diǎn)。樓主用下圖來(lái)表示循環(huán)鏈表:
修改構(gòu)造方法:
function LinkedList(){ this.head = new Node('head');//初始化 this.head.next = this.head;//直接將頭節(jié)點(diǎn)的next指向頭節(jié)點(diǎn)形成循環(huán)鏈表 this.find = find; this.frontNode = frontNode; this.insert = insert; this.remove = remove; this.show = show; }
這時(shí)需要注意鏈表的輸出方法show()與find()方法,原來(lái)的方式在循環(huán)鏈表里會(huì)陷入死循環(huán),while循環(huán)的循環(huán)條件需要修改為當(dāng)循環(huán)到頭節(jié)點(diǎn)時(shí)退出循環(huán)。
function find(item){ var currentNode = this.head;//從頭結(jié)點(diǎn)開(kāi)始 while(currentNode.element!=item&¤tNode.next.element!='head'){ currentNode = currentNode.next; } return currentNode;//找到返回結(jié)點(diǎn)數(shù)據(jù),沒(méi)找到返回null } function show(){ var currentNode = this.head,result = ""; while (currentNode.next != null && currentNode.next.element != "head") { result += currentNode.next.element + " "; currentNode = currentNode.next; } return result; }
測(cè)試程序:
var list = new LinkedList(); list.insert("a","head"); list.insert("b","a"); list.insert("c","b"); console.log(list.show()); list.remove("b"); console.log(list.show());
測(cè)試結(jié)果:
本文用到的示例代碼地址:https://github.com/LJunChina/JavaScript
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
- JavaScript數(shù)據(jù)結(jié)構(gòu)之雙向鏈表
- JavaScript數(shù)據(jù)結(jié)構(gòu)之雙向鏈表和雙向循環(huán)鏈表的實(shí)現(xiàn)
- JavaScript數(shù)據(jù)結(jié)構(gòu)之單鏈表和循環(huán)鏈表
- JavaScript數(shù)據(jù)結(jié)構(gòu)之雙向鏈表定義與使用方法示例
- 使用JavaScript實(shí)現(xiàn)鏈表的數(shù)據(jù)結(jié)構(gòu)的代碼
- JavaScript數(shù)據(jù)結(jié)構(gòu)鏈表知識(shí)詳解
- JavaScript數(shù)據(jù)結(jié)構(gòu)與算法之鏈表
- JavaScript實(shí)現(xiàn)的鏈表數(shù)據(jù)結(jié)構(gòu)實(shí)例
- JavaScript數(shù)據(jù)結(jié)構(gòu)之鏈表各種操作詳解
相關(guān)文章
JavaScript中事件流冒泡的原理與實(shí)現(xiàn)
在JavaScript中,事件流冒泡是一種非常重要的概念,它是指事件從最內(nèi)層的元素開(kāi)始,逐級(jí)向外傳播到最外層元素的過(guò)程,下面我們就來(lái)了解下JavaScript中事件流冒泡的原理與實(shí)現(xiàn)吧2023-11-11JS獲取指定時(shí)間的時(shí)間戳的方法匯總(最新整理收藏版)
在JavaScript中,可以使用Date.parse()或new Date()來(lái)獲取指定時(shí)間的時(shí)間戳,本文給大家分享JS獲取指定時(shí)間的時(shí)間戳的方法,感興趣的朋友一起看看吧2024-01-01js實(shí)現(xiàn)html table 行,列鎖定的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇js實(shí)現(xiàn)html table 行,列鎖定的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-10-10高性能WEB開(kāi)發(fā) flush讓頁(yè)面分塊,逐步呈現(xiàn) flush讓頁(yè)面分塊,逐步呈現(xiàn)
在處理比較耗時(shí)的請(qǐng)求的時(shí)候,我們總希望先讓用戶先看到部分內(nèi)容,讓用戶知道系統(tǒng)正在進(jìn)行處理,而不是無(wú)響應(yīng)。2010-06-06詳解JavaScript中Generator函數(shù)的使用
Generator 是 ES6 新增的一種函數(shù)類(lèi)型,這篇文章主要來(lái)和大家詳細(xì)聊聊Generator函數(shù)的具體用法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-06-06利用uniapp+vue3+js適配微信隱私協(xié)議開(kāi)發(fā)指南
這篇文章主要給大家介紹了關(guān)于利用uniapp+vue3+js適配微信隱私協(xié)議開(kāi)發(fā)指南的相關(guān)資料,適配最新微信小程序隱私協(xié)議開(kāi)發(fā)指南,兼容uniapp版本,需要的朋友可以參考下2023-12-12JavaScript中while循環(huán)的基礎(chǔ)使用教程
這篇文章主要給大家介紹了關(guān)于JavaScript中while循環(huán)的基礎(chǔ)使用教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用JavaScript具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08