欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

這篇文章給大家分享的是有關(guān)JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

創(chuàng)新互聯(lián)科技有限公司專業(yè)互聯(lián)網(wǎng)基礎(chǔ)服務(wù)商,為您提供成都服務(wù)器托管,高防服務(wù)器,成都IDC機(jī)房托管,成都主機(jī)托管等互聯(lián)網(wǎng)服務(wù)。

在本文中,我們將討論如何將鏈表存儲在數(shù)據(jù)庫中,實(shí)現(xiàn)鏈表的添加和刪除,查找以及反轉(zhuǎn)鏈表等操作。 在實(shí)現(xiàn)鏈表之前,需要知道相比數(shù)組和對象,鏈表的優(yōu)點(diǎn)是什么。

我們知道,數(shù)組中的元素以索引編號和順序存儲在數(shù)據(jù)庫中:

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

在使用數(shù)組時,在開始或特定索引處添加/刪除元素這樣的操作可能是一項(xiàng)性能較低的任務(wù),因?yàn)槲覀儽仨氁苿铀衅渌氐乃饕?,造成這種原因是由數(shù)組的編號索引特性導(dǎo)致的。

使用對象可以解決上述問題。 由于在對象中,元素存儲位置是隨機(jī)的,因此,在執(zhí)行諸如在開始處或特定索引處添加/刪除元素之類的操作時,無需移動元素的索引:

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

盡管在對象中添加和刪除元素速度很快,但是從上圖可以看出,在進(jìn)行迭代操作時,對象并不是最佳選擇,因?yàn)閷ο蟮脑卮鎯υ陔S機(jī)位置。 因此,迭代操作可能需要很長時間。 這是鏈表引出的原因。

那么什么是鏈表呢 ?

從名字本身可以看出它是一個以某種方式鏈表。 那么它是如何鏈接的,列表包含什么呢?

鏈表由具有兩個屬性的節(jié)點(diǎn)組成:數(shù)據(jù)和指針。

節(jié)點(diǎn)內(nèi)的指針指向列表中的下一個節(jié)點(diǎn)。 鏈表中的第一個節(jié)點(diǎn)稱為head。 為了更好地理解,讓我們看一下描述鏈表圖示:

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

從上圖可以看出,每個節(jié)點(diǎn)都有兩個屬性,datapointer。 指針指向列表中的下一個節(jié)點(diǎn),最后一個節(jié)點(diǎn)的指針指向null,上圖是一個單鏈表?。

鏈表和對象時有很大的不同。 在鏈表中,每個節(jié)點(diǎn)都通過指針(pointer)連接到下一個節(jié)點(diǎn)。 因此,我們在鏈表的每個節(jié)點(diǎn)之間都有連接,而在對象中,鍵值對是隨機(jī)存儲的,彼此之間沒有連接。

接著,我們實(shí)現(xiàn)一個存儲整數(shù)的鏈表。 由于 JS 不提供內(nèi)置的鏈表支持,因此我們將使用對象和類來實(shí)現(xiàn)鏈表 ?

class Node {
  constructor (value) {
    this.value = value
    this.next = null
  }
}

class LinkedList {
  constructor () {
    this.head = null
    this.tail = this.head
    this.length = 0
  }
  append (value) {
  }

  prepend (value) {

  }

  insert (value, index) {

  }

  lookup (index) {

  }

  remove (index) {

  }

  reverse () {
    
  }
}

在上面的代碼中,我們創(chuàng)建了兩個類,一個用于來鏈表本身,一個是節(jié)點(diǎn)本身。 如我們所討論的,每個節(jié)點(diǎn)將具有兩個屬性,一個和一個指針(對應(yīng) next 字段)。

LinkedList類包含三個屬性,head(初始值為null),用于存儲鏈表的最后一個節(jié)點(diǎn)的tail(也指向null)和用于保存鏈表長度的length屬性。接著,我們來實(shí)現(xiàn)里面的方法 ?。

append (按順序添加值)

這個函數(shù)將一個節(jié)點(diǎn)添加到鏈表的末尾。為了實(shí)現(xiàn)這個函數(shù),我們需要理解它需要執(zhí)行的一些操作:

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

從上圖中,我們可以通過以下方式實(shí)現(xiàn)append函數(shù):

  append (value) {
    const newNode = new Node(value)
    if (!this.head) {
      this.head = newNode
      this.tail = newNode
    } else {
      this.tail.next = newNode
      this.tail = newNode
    }
    this.length++
  }

簡單的對 append 方法解釋一下 ?:

const linkedList1 = new LinkedList()
linkedList1.append(2)

檢查head是否指向null,此時的head指向null,因此我們創(chuàng)建一個新對象,并將新對象分配給headtail:

let node = new Node(2)
this.head = newNode
this.tail = newNode

現(xiàn)在,headtail 都指向同一個對象,這一點(diǎn)很重要,要記住。

接著,我們再向鏈表添加兩個值:

linkedList1.append(3)
linkedList1.append(4)

現(xiàn)在,head 不指向null,所以我們進(jìn)入append函數(shù)的else分支:

this.tail.next = node

由于headtail 都指向同一個對象,tail的變化都會導(dǎo)致head對象的變化,這是JS 中對象的工作方式。在JavaScript中,對象是通過引用傳遞的,因此 headtail都指向存儲對象的相同地址空間。上面這行代碼相當(dāng)于

this.head.next = node;

下一行:

this.tail = node

現(xiàn)在,在執(zhí)行完上面的代碼行之后,this.head.nextthis.tail指向同一對象,因此,每當(dāng)我們添加新節(jié)點(diǎn)時,head對象都會自動更新。

執(zhí)行三次append之后,linkedList1 的結(jié)構(gòu)應(yīng)該是這樣的:

head: {value: 2 , next: {value: 3, next: {value: 4,next: null}}}
tail : {value: 4, next: null}
length:3

從上面的代碼中我們可以看到,鏈表的append函數(shù)的復(fù)雜度是O(1),因?yàn)槲覀兗炔恍枰苿铀饕?,也不需要遍歷鏈表。

我們來看下一個函數(shù) ?

prepend (將值添加到鏈表的開頭)

為了實(shí)現(xiàn)此函數(shù),我們使用Node類創(chuàng)建一個新節(jié)點(diǎn),并將該新節(jié)點(diǎn)的下一個對象指向鏈表的head 。 接下來,我們將新節(jié)點(diǎn)分配給鏈表的head

與append函數(shù)一樣,這個函數(shù)的復(fù)雜度也是O(1)。

  prepend (value) {
  const node = new Node(value)

  node.next = this.head
  this.head = node
  this.length++
}

就像append函數(shù)一樣,此函數(shù)的復(fù)雜度也為O(1)。

insert (在特定索引處添加值)

在實(shí)現(xiàn)此函數(shù)之前,我們先看看它的一個轉(zhuǎn)化過程。因此,出于理解目的,我們先創(chuàng)建一個值很少的鏈表,然后可視化insert函數(shù)。 insert  函數(shù)接受兩個參數(shù),值和索引:

let linkedList2 = new LinkedList()
linkedList2.append(23)
linkedList2.append(89)
linkedList2.append(12)
linkedList2.append(3)
linkedList2.insert(45,2)

第1步:

遍歷鏈表,直到到達(dá)index-1位置:

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

第2步:

將索引為1的節(jié)點(diǎn)的指針(在本例中為89)分配給新節(jié)點(diǎn)(在本例中為45):

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

第3步:

將新節(jié)點(diǎn)(45)的 next 指向給下一個節(jié)點(diǎn)(12)

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

這就是執(zhí)行插入操作的方式。 通過以上可視化,我們觀察到需要在index-1位置和index位置找到節(jié)點(diǎn),以便可以在它們之間插入新節(jié)點(diǎn)。 在代碼中實(shí)現(xiàn):

insert (value, index) {
  if (index >= this.length) {
  this.append(value)
}

  const node = new Node(value)

  const { prevNode, nextNode } = thisg.getPrevNextNodes(index)
  prevNode.next = node
  node.next = nextNode

  this.length++
}

簡單分析一下上面的函數(shù):

如果index的值大于或等于length屬性,則將操作移交給append函數(shù)。 對于 else 分支,我們使用 Node 類創(chuàng)建一個新節(jié)點(diǎn),接下來觀察一個新函數(shù)getPrevNextNodes() ,通過該函數(shù)我們可以接收prevNodenextNode的值。 getPrevNextNodes函數(shù)的實(shí)現(xiàn)如下:

 getPrevNextNodes(index){
    let count = 0;
    let prevNode = this.head;
    let nextNode = prevNode.next;

    while(count < index - 1){
      prevNode = prevNode.next;
      nextNode = prevNode.next;
      count++;
    }

    return {
      prevNode,
      nextNode
    }
  }

通過遍歷鏈表返回在index-1位置和index位置的節(jié)點(diǎn),并將prevNodenext屬性指向新節(jié)點(diǎn),并將新節(jié)點(diǎn)的next屬性指向nextNode。

鏈表的插入操作的復(fù)雜度為 O(n),因?yàn)槲覀儽仨毐闅v鏈表并在index-1index 位置搜索節(jié)點(diǎn)。 盡管復(fù)雜度為O(n),但我們發(fā)現(xiàn)此插入操作比對數(shù)組的插入操作快得多,在數(shù)組中,我們必須將所有元素的索引移到特定索引之后,但是在鏈接中,我們僅操縱 index-1index 位置的節(jié)點(diǎn)的下一個屬性。

remove (刪除特定索引處的元素)

實(shí)現(xiàn)了插入操作之后,刪除操作就比較容易理解,因?yàn)樗鼛缀跖c插入操作相同,當(dāng)我們從getPrevNextNodes函數(shù)獲取prevNodenextNode值時,我們必須在remove中執(zhí)行以下操作:

remove(index){
  let {previousNode,currentNode} = this.getNodes(index)
  previousNode.next = currentNode.next
  this.length--
}

刪除操作的復(fù)雜度也為 O(n),類似于插入操作,鏈表中的刪除操作比數(shù)組中的刪除操作要快。

reverse (反轉(zhuǎn)鏈表)

雖然看起來很簡單,但反轉(zhuǎn)鏈表常常是實(shí)現(xiàn)起來最令人困惑的操作,因此,在面試中會經(jīng)常詢問這個操作。在實(shí)現(xiàn)這個函數(shù)之前,讓我們先把反轉(zhuǎn)鏈表的策略可視化一下。

為了反轉(zhuǎn)鏈表,我們需要跟蹤三個節(jié)點(diǎn),previousNode,currentNodenextNode。

考慮下面的鏈表:

let linkedList2 = new LinkedList()
linkedList2.append(67)
linkedList2.append(32)
linkedList2.append(44)

第一步:

開始,previousNode的值為null,而currentNode的值為head

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

第二步:

接下來,我們將nextNode分配給currentNode.next

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

第三步:

接下來,我們將currentNode.next屬性指向previousNode

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

第三步:

現(xiàn)在,我們將previousNode移至currentNode,將currentNode移至nextNode

JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么

這個過程從步驟2重復(fù)操作,一直到currentNode 等于 null。

reverse (){
  let previousNode = null
  let currentNode = this.head

  while(currentNode !== null) {
    let nextNode = currentNode.next
    currentNode.next = previousNode
    previousNode = currentNode
    currentNode = nextNode
  }

  this.head = previousNode
}

就像我們看到的一樣,直到currentNode === null,我們一直在遍歷和移動這些值。 最后,我們將previousNode值分配給head。

反向運(yùn)算的復(fù)雜度為O(n)。

查找 (查找特定索引的值)

這個操作很簡單,我們只是遍歷鏈表并返回特定索引處的節(jié)點(diǎn)。這個操作的復(fù)雜度也是O(n)。

lookup(index){
    let counter = 0;
    let currentNode = this.head;
    while(counter < index){
      currentNode = currentNode.next;
      counter++;
    }
    return currentNode;
  }

好了,我們已經(jīng)完成了用javascript實(shí)現(xiàn)單個鏈表的基本操作。單鏈表和雙鏈表的區(qū)別在于,雙鏈表的節(jié)點(diǎn)具有指向前一個節(jié)點(diǎn)和下一個節(jié)點(diǎn)的指針。

鏈表為我們提供了快速的append(末尾添加元素)和prepend(開頭添加元素)操作。 盡管鏈表中的插入操作的復(fù)雜度為O(n),但比數(shù)組的插入操作要快得多。 使用數(shù)組時我們面臨的另一個問題是大小復(fù)雜性,當(dāng)使用動態(tài)數(shù)組時,在添加元素時,我們必須將整個數(shù)組復(fù)制到另一個地址空間,然后添加元素,而在鏈表中,我們不需要 面對這樣的問題。

在使用對象時,我們面臨的問題是元素在內(nèi)存中的隨機(jī)位置,而在鏈表中,節(jié)點(diǎn)是通過指針相互連接的,指針提供了一定的順序。

感謝各位的閱讀!關(guān)于“JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

標(biāo)題名稱:JS數(shù)據(jù)結(jié)構(gòu)之鏈表的優(yōu)點(diǎn)是什么
文章URL:http://chinadenli.net/article36/giodpg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供用戶體驗(yàn)、網(wǎng)站營銷、搜索引擎優(yōu)化、服務(wù)器托管、企業(yè)建站、企業(yè)網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計(jì)公司