javascript 实现链表

javascript 实现链表

链表存储有序的元素集合,但不同于数组,链表中的元素在内存中并不是连续放置的。每个 元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。

相对于传统的数组,链表的一个好处在于,添加或移除元素的时候不需要移动其他元素。然 而,链表需要使用指针,因此实现链表时需要额外注意。数组的另一个细节是可以直接访问任何 位置的任何元素,而要想访问链表中间的一个元素,需要从起点(表头)开始迭代列表直到找到 所需的元素。 现实中也有一些链表的例子。第一个例子就是康加舞队。每个人是一个元素,手就是链向下 一个人的指针。可以向队列中增加人——只需要找到想加入的点,断开连接,插入一个人,再重 新连接起来。

另一个例子是寻宝游戏。你有一条线索,这条线索是指向寻找下一条线索的地点的指针。你顺着这条链接去下一个地点,得到另一条指向再下一处的线索。得到列表中间的线索的唯一办法, 就是从起点(第一条线索)顺着列表寻找。 还有一个可能是用来说明链表的最流行的例子,那就是火车。一列火车是由一系列车厢(也 称车皮)组成的。每节车厢或车皮都相互连接。你很容易分离一节车皮,改变它的位置,添加或 移除它。

创建一个链表

function LinkedList() {
  // 一个辅助类,表示一个节点,包含一个指针,指向下一个节点
  var Node = function(element) {
    this.element = element
    this.next = null
  }
  // 表示列表项的长度
  var length = 0
  // 第一个节点的引用
  var head = null
  // 向链表尾部添加一个新的项
  this.append = function(element) {
    // 创建一个节点
    var node = new Node(element),
      current //用于暂存当前项
    //如果是空链表 那么 直接让head成为一个节点head.next自动变成null
    if (head === null) {
      //列表中第一个节点
      head = node
    } else {
      // 当前的head不为null,说明当前的head有next属性
      current = head
      // 循环链表找到最后一项
      while (current.next) {
        current = current.next
      }
      // 当curent.next等于空时说明已经到了最后一项
      // 然后把node赋值给最后一项即可
      current.next = node
    }
    // 更新长度
    length++
  }
  // 向链表的特定位置插入一个新的项
  this.insert = function(position, element) {
    //检查越界值
    if (position >= 0 && position <= length) {
      var node = new Node(element),
        current = head,
        previous,
        index = 0
      //在第一个位置添加
      //current是对链表中第一个元素的引用
      if (position === 0) {
        // 现在head和node.next都指向了current
        node.next = current
        // 把head的引用改为node
        head = node
      } else {
        // 当跳出循环时,current变量将是对想要插入新元素的位置之后一个 元素的引用,
        // 而previous将是对想要插入新元素的位置之前一个元素的引用。
        while (index++ < position) {
          previous = current
          current = current.next
        }
        // 因此,首先需要把新项(node)和当前项链接起来,然后需要改变previous和current之间的链接。
        // 我们还需要让previous.next 指向node。
        node.next = current
        previous.next = node
      }
      //更新长度
      length++

      return true
    } else {
      return false
    }
  }
  // 从链表中移除一项
  this.remove = function(element) {}
  // 从链表中的特定位置移除一项
  this.removeAt = function(position) {
    //检查越界值
    if (position > -1 && positon < length) {
      var current = head, //暂存当前项
        previous, //暂存之前项
        index = 0 //索引
      // 如果移除第一项,直接让head置空即可
      if (position === 0) {
        head = current.next
      } else {
        // 迭代链表
        while (index++ < position) {
          // 用previous(上一个)暂存current(当前项),当前项指向下一项
          previous = current
          current = current.next
        }
        //将previous(上一个))与current(当前的)的下一项连接起来;跳过current,从而移除它
        previous.next = current.next
      }
      // 更新长度
      length--
      return current.element
    } else {
      return null
    }
    // current变量是对要移除元素的引用。previous变量是对要移除元素的前一个元素的引用。
    // 那么要移除current元素,需要做的就是将previous.next与current.next链接起来。
    // 因此, 我们的逻辑对这两种情况都管用。
  }
  // 返回元素在链表中的索引
  this.indexOf = function(element) {
    var current = head,
      index = -1
    while (current) {
      if (element === current.element) {
        return index
      }
      index++
      current = current.next
    }
    return -1
  }
  // 返回链表是否为空
  this.isEmpty = function() {
    return length === 0
  }
  // 返回链表中的元素个数
  this.size = function() {
    return length
  }
  // 输出值
  this.toString = function() {
    var current = head,
      string = ''
    while (current) {
      string = current.element
      current = current.next
    }
    return string
  }
  this.getHead = function() {
    return head
  }
  this.print = function() {}
}

双向链表


function DoublyLinkedList() {
  var Node = function(element) {
    this.element = element
    this.next = null
    this.prev = null
  }

  var length = 0
  var head = null
  var tail = null

  this.insert = function(position, element) {
    if (position >= 0 && position <= length) {
      var node = new Node(element),
        current = head,
        previous,
        index = 0

      if (position === 0) {
        if (!head) {
          //1
          head = node
          tail = node
        } else {
          node.next = current
          current.prev = node //2
          head = node
        }
      } else if (position === length) {
        current = tail //3
        current.next = node
        node.prev = current
        tail = node
      } else {
        while (index++ < position) { //4
          previous = current
          current = current.next
        }
        node.next = current //5
        previous.next = node

        current.prev = node
        node.prev = previous
      }
      length++
      return true
    } else {
      return false
    }
  }
}