摘要:在存儲(chǔ)多個(gè)元素時(shí),我們最常用的數(shù)據(jù)結(jié)構(gòu)可能是數(shù)組,究其原因可能是數(shù)組訪問方便,可以直接通過訪問,但是數(shù)組也存在一定的缺點(diǎn),數(shù)組的大小是固定,數(shù)組在執(zhí)行插入或者刪除的時(shí)候成本很高。
在存儲(chǔ)多個(gè)元素時(shí),我們最常用的數(shù)據(jù)結(jié)構(gòu)可能是數(shù)組,究其原因可能是數(shù)組訪問方便,可以直接通過[]訪問,但是數(shù)組也存在一定的缺點(diǎn),數(shù)組的大小是固定,數(shù)組在執(zhí)行插入或者刪除的時(shí)候成本很高。
鏈表存儲(chǔ)的是有序的元素集合,和數(shù)組不同的是,鏈表中的元素在內(nèi)存并不是連續(xù)放置,每個(gè)元素由一個(gè)存儲(chǔ)元素本身的節(jié)點(diǎn)和一個(gè)指向下一個(gè)元素的引用組成,結(jié)構(gòu)如下圖所示:
和數(shù)組相比,鏈表的優(yōu)勢在于:添加或者刪除元素不需要移動(dòng)其他元素,劣勢在與鏈表相對于數(shù)組結(jié)構(gòu)更復(fù)雜,需要一個(gè)指向下一個(gè)元素的指針,在訪問鏈表中的某個(gè)元素也需要從頭迭代,而不是像數(shù)組一樣直接訪問
首先讓我們來看一下鏈表的大概骨架,需要定義一些什么屬性:
function LinkedList() { let Node = function (element) { this.element = element this.next = null } let length = 0 let head = null this.append = function (element) { } this.insert = function (position, element) { } this.removeAt = function (position) { } this.remove = function (element) { } this.indexOf = function (element) { } this.isEmpty = function () { } this.size = function () { } this.getHead = function () { } this.toString = function () { } this.print = function () { } }
首先LinkedList里面需要定義一個(gè)Node輔助類,表示要加入鏈表的項(xiàng),包含一個(gè)element屬性和一個(gè)指向下一個(gè)節(jié)點(diǎn)的指針next,接下來定義了一個(gè)指針的頭head和指針的長度length,然后就是最重要的類里面的方法,接下來就讓我們一起來看這些方法的職責(zé)和實(shí)現(xiàn)
append(向鏈表尾部追加元素)鏈表在向尾部追加元素的時(shí)候有兩種情況:鏈表為空,添加的是第一個(gè)元素,或者鏈表不為空,追加元素,下面來看具體實(shí)現(xiàn):
this.append = function (element) { let node = new Node(element), current if (head === null) { head = node // 鏈表為空時(shí),插入 } else { current = node while (current.next) { // 循環(huán)鏈表,直到最后一項(xiàng) current = current.next } current.next = node // 找到最后一項(xiàng),將新增元素連接 } length++ }
現(xiàn)在讓我們先來看第一個(gè)種情況,鏈表為空時(shí),插入就直接是頭,因此直接將node賦值給head就行,第二種情況,當(dāng)鏈表有元素時(shí),就需要先循環(huán)鏈表,找到最后一項(xiàng),然后將最后一項(xiàng)的next指針指向node
removeAt(移除元素)現(xiàn)在讓我們來看看怎么從指定位置移除元素,移除元素也有兩個(gè)場景,第一種是移除第一個(gè)元素,第二種是移除第一個(gè)以外的任意一個(gè)元素,來看具體實(shí)現(xiàn):
this.removeAt = function (position) { if (position > -1 && position < length) { // 判斷邊界 let previous, index = 0, current = head if (position === 0) { // 移除第一項(xiàng) head = current.next } else { while (index++ < position) { previous = current current = current.next } previous.next = current.next } length-- return current.element } else { return null } }
接下來一起來分析一下上面的代碼,首先判斷要?jiǎng)h除的位置是不是有效的位置,然后來看第一種情況,當(dāng)移除的元素是第一項(xiàng)是時(shí),此時(shí)直接將head指向第二個(gè)元素就行了,第二種情況就會(huì)稍微復(fù)雜一點(diǎn),首先需要一個(gè)index控制遞增,previous記錄前一個(gè)位置,移除當(dāng)前元素,就是將前一個(gè)元素的next指向下一個(gè)元素,來看一個(gè)示意圖:
因此在while循環(huán)中始終用previous記錄上一個(gè)位置元素,current記錄下一個(gè)元素,跳出循環(huán)時(shí),上一個(gè)元素的next指針指向當(dāng)前元素的next指針指向的元素,就將當(dāng)前元素移出鏈表
接下來來看在任意位置插入的insert方法,這個(gè)方法同樣需要考慮兩種情況,插入位置在頭部和插入位置不在頭部,下面來看一下具體實(shí)現(xiàn):
this.insert = function (position, element) { if (position > -1 && position <= length) { let node = new Node(element),previous, index = 0, current = head if (position === 0) { node.next = current head = node } else { while (index++ < position) { previous = current current = current.next } previous.next = node node.next = current } length++ return true } else { return false } }
先來看第一種情況,鏈表起點(diǎn)添加一個(gè)元素,將node.next指向current,然后再將node的引用賦值給head,這樣就再鏈表的起點(diǎn)添加了一個(gè)元素,第二種情況,在其他位置插入一個(gè)元素,previous是插入元素的前一個(gè)元素,current為插入元素的后一個(gè)元素,想要插入一個(gè)元素,就需要將前一個(gè)元素的next指向要插入的元素,要插入元素的next指向下一個(gè)元素,來看示意圖:
如上圖所示:將新項(xiàng)node插入到previous和current之間,需要將previous.next指向node,node.next指向current,這樣就在鏈表中插入了一個(gè)新的項(xiàng)
toString方法會(huì)把LinkedList對象轉(zhuǎn)換成一個(gè)字符串,下面來看具體實(shí)現(xiàn):
this.toString = function () { let current = head, string = "" while (current) { string += current.element + (current.next ? "n" : "") current = current.next } return string }
循環(huán)遍歷所有元素,以head為起點(diǎn),當(dāng)存在下一個(gè)元素時(shí),就將其拼接到字符串中,直到next為null
indexOfindexOf方法返回對應(yīng)元素的位置,存在就返回對應(yīng)的索引,不存在返回-1,來看具體的實(shí)現(xiàn):
this.indexOf = function (element) { let current = head, index = 0 while (current) { if (current.element === element) { return index } index++ current = current.next } return -1 }
遍歷鏈表,當(dāng)前元素的值與目標(biāo)值一致時(shí)返回元素的位置index,遍歷完鏈表還沒找到則返回-1
remove、isEmpty、size、getHead由于這幾個(gè)方法實(shí)現(xiàn)比較簡單,直接來看具體實(shí)現(xiàn):
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 }總結(jié)
這篇文章主要對鏈表做了簡單介紹,對鏈表的簡單實(shí)現(xiàn)。如果有錯(cuò)誤或不嚴(yán)謹(jǐn)?shù)牡胤剑瑲g迎批評指正,如果喜歡,歡迎點(diǎn)贊。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/102042.html
摘要:我對鏈表的學(xué)習(xí)什么是鏈表要存儲(chǔ)多個(gè)元素,數(shù)組可能是最常用的數(shù)據(jù)結(jié)構(gòu)。鏈表的學(xué)習(xí)創(chuàng)建一個(gè)鏈表各種方法表示要加入列表的項(xiàng),它包含一個(gè)屬性以及一個(gè)屬性,表示要添加到列表的值,表示指向列表下一個(gè)節(jié)點(diǎn)項(xiàng)的指針。 我對JS鏈表的學(xué)習(xí) 什么是鏈表 要存儲(chǔ)多個(gè)元素,數(shù)組可能是最常用的數(shù)據(jù)結(jié)構(gòu)。這種數(shù)據(jù)結(jié)構(gòu)非常方便,但是有一個(gè)缺點(diǎn):從數(shù)組的起點(diǎn)或者中間插入或移除項(xiàng)的成本非常高,因?yàn)樾枰苿?dòng)元素(比如你插...
摘要:對散列表的簡單學(xué)習(xí)類也叫類,是類的一種散列表實(shí)現(xiàn)方式。鍵值散列函數(shù)散列值形成散列表地址數(shù)據(jù)鍵值對相關(guān)操作方法創(chuàng)建一個(gè)散列表實(shí)現(xiàn)一個(gè)散列函數(shù),即將碼值相加的方法。 對JS散列表的簡單學(xué)習(xí) HashTable類也叫HashMap類,是Dictionary類的一種散列表實(shí)現(xiàn)方式。 散列算法的作用是盡可能快的在數(shù)據(jù)結(jié)構(gòu)中找到一個(gè)值。 在之前的學(xué)習(xí)中,如果你想要獲得數(shù)據(jù)結(jié)構(gòu)中的一個(gè)值,需要遍歷整...
摘要:上一篇數(shù)據(jù)結(jié)構(gòu)與算法棧隊(duì)列下一篇數(shù)據(jù)結(jié)構(gòu)與算法集合字典寫在前面說明數(shù)據(jù)結(jié)構(gòu)與算法系列文章的代碼和示例均可在此找到上一篇博客發(fā)布以后,僅幾天的時(shí)間竟然成為了我寫博客以來點(diǎn)贊數(shù)最多的一篇博客。 上一篇:JS數(shù)據(jù)結(jié)構(gòu)與算法_棧&隊(duì)列下一篇:JS數(shù)據(jù)結(jié)構(gòu)與算法_集合&字典 寫在前面 說明:JS數(shù)據(jù)結(jié)構(gòu)與算法 系列文章的代碼和示例均可在此找到 上一篇博客發(fā)布以后,僅幾天的時(shí)間竟然成為了我寫博客以...
摘要:技巧使你的更加專業(yè)這是上關(guān)于技巧的一篇譯文,另外你也可以在本項(xiàng)目看到原文。列舉了一些很實(shí)用的技巧,比如給空內(nèi)容的標(biāo)簽添加內(nèi)容,逗號分隔列表等等。排序算法看源碼,把它背下來吧排序算法的封裝。主要幫助初學(xué)者更好的掌握排序算法的實(shí)現(xiàn)。 成為專業(yè)程序員路上用到的各種優(yōu)秀資料、神器及框架 成為一名專業(yè)程序員的道路上,需要堅(jiān)持練習(xí)、學(xué)習(xí)與積累,技術(shù)方面既要有一定的廣度,更要有自己的深度。 Java...
閱讀 1867·2021-11-18 10:02
閱讀 3586·2021-11-16 11:45
閱讀 1883·2021-09-10 10:51
閱讀 2193·2019-08-30 15:43
閱讀 1432·2019-08-30 11:23
閱讀 1544·2019-08-29 11:07
閱讀 1961·2019-08-23 17:05
閱讀 1564·2019-08-23 16:14