JS数据结构进修:链表

在存储多个元素时,我们最经常使用的数据构造多是数组,究其原因多是数组接见轻易,能够直接经由过程[]接见,然则数组也存在肯定的瑕玷,数组的大小是牢固,数组在实行插进去或许删除的时刻本钱很高。

链表存储的是有序的元素鸠合,和数组差别的是,链表中的元素在内存并非一连安排,每一个元素由一个存储元素自身的节点和一个指向下一个元素的援用构成,构造如下图所示:
《JS数据结构进修:链表》
和数组比拟,链表的上风在于:增加或许删除元素不须要挪动其他元素,劣势在与链表相对于数组构造更庞杂,须要一个指向下一个元素的指针,在接见链表中的某个元素也须要重新迭代,而不是像数组一样直接接见

链表的建立

起首让我们来看一下链表的也许骨架,须要定义一些什么属性:

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内里须要定义一个Node辅佐类,示意要到场链表的项,包括一个element属性和一个指向下一个节点的指针next,接下来定义了一个指针的头head和指针的长度length,然后就是最主要的类内里的要领,接下来就让我们一同来看这些要领的职责和完成

append(向链表尾部追加元素)

链表在向尾部追加元素的时刻有两种状况:链表为空,增加的是第一个元素,或许链表不为空,追加元素,下面来看详细完成:

this.append = function (element) {
    let node = new Node(element), current
    if (head === null) {
      head = node // 链表为空时,插进去
    } else {
      current = node
      while (current.next) { // 轮回链表,直到末了一项
        current = current.next
      }
      current.next = node // 找到末了一项,将新增元素衔接
    }
    length++
  }

如今让我们先来看第一个种状况,链表为空时,插进去就直接是头,因而直接将node赋值给head就行,第二种状况,当链表有元素时,就须要先轮回链表,找到末了一项,然后将末了一项的next指针指向node

removeAt(移除元素)

如今让我们来看看怎样从指定位置移除元素,移除元素也有两个场景,第一种是移除第一个元素,第二种是移除第一个之外的恣意一个元素,来看详细完成:

this.removeAt = function (position) {
    if (position > -1 && position < length) { // 推断边境
      let previous, index = 0, current = head
      if (position === 0) { // 移除第一项
        head = current.next
      } else {
        while (index++ < position) {
          previous = current
          current = current.next
        }
        previous.next = current.next
      }
      length--
      return current.element
    } else {
      return null
    }
  }

接下来一同来剖析一下上面的代码,起首推断要删除的位置是不是是有用的位置,然后来看第一种状况,当移除的元素是第一项是时,此时直接将head指向第二个元素就好了,第二种状况就会轻微庞杂一点,起首须要一个index掌握递增,previous纪录前一个位置,移除当前元素,就是将前一个元素的next指向下一个元素,来看一个示意图:
《JS数据结构进修:链表》
因而在while轮回中一直用previous纪录上一个位置元素,current纪录下一个元素,跳出轮回时,上一个元素的next指针指向当前元素的next指针指向的元素,就将当前元素移出链表

insert(恣意位置插进去)

接下来来看在恣意位置插进去的insert要领,这个要领一样须要斟酌两种状况,插进去位置在头部和插进去位置不在头部,下面来看一下详细完成:

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
    }
  }

先来看第一种状况,链表出发点增加一个元素,将node.next指向current,然后再将node的援用赋值给head,如许就再链表的出发点增加了一个元素,第二种状况,在其他位置插进去一个元素,previous是插进去元素的前一个元素,current为插进去元素的后一个元素,想要插进去一个元素,就须要将前一个元素的next指向要插进去的元素,要插进去元素的next指向下一个元素,来看示意图:
《JS数据结构进修:链表》
如上图所示:将新项node插进去到previous和current之间,须要将previous.next指向node,node.next指向current,如许就在链表中插进去了一个新的项

toString

toString要领会把LinkedList对象转换成一个字符串,下面来看详细完成:

this.toString = function () {
    let current = head, string = ''
    while (current) {
      string += current.element + (current.next ? 'n' : '')
      current = current.next
    }
    return string
  }

轮回遍历一切元素,以head为出发点,当存在下一个元素时,就将其拼接到字符串中,直到next为null

indexOf

indexOf要领返回对应元素的位置,存在就返回对应的索引,不存在返回-1,来看详细的完成:

this.indexOf = function (element) {
    let current = head, index = 0
    while (current) {
      if (current.element === element) {
        return index
      }
      index++
      current = current.next
    }
    return -1
  }

遍历链表,当前元素的值与目标值一致时返回元素的位置index,遍历完链表还没找到则返回-1

remove、isEmpty、size、getHead

因为这几个要领完成比较简朴,直接来看详细完成:

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
  }

总结

这篇文章主要对链表做了简朴引见,对链表的简朴完成。假如有毛病或不严谨的处所,迎接批评指正,假如喜好,迎接点赞。

    原文作者:william
    原文地址: https://segmentfault.com/a/1190000018260869
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞