JS实现双链表

链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题。插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构。尽管从链表中头节点遍历到尾节点很容易,但是反过来,从后向前遍历就没有那么简单。我们可以通过给Node对象增加一个属性,该属性存储指向前驱节点的链接,这样就容易多了。此时向链表中插入一个节点需要更多的工作,我们需要指出该节点正确的前驱和后续。但是在从链表中删除节点的时候效率更高了,不需要再查找待删除节点的前驱节点了。双链表的图解如下:
双链表

用JS设计一个双链表

我们需要设计两个类,Node 类用来表示节点,LinkedList类提供插入节点、删除节点、显示列表元素的方法,以及其他一些辅助方法。

Node类:
function Node(element){
  this.element = element
  this.next = null
  this.previous = null
}
LinkedList类:
function LinkedList(){
  this.head = new Node('head')  // 头节点
}
用LinkedList的原型对象存储操作链表的方法:
LinkedList.prototype = {
  // 查找某一节点
  find: function(item){
    var currentNode = this.head
    while (currentNode.element !== item) {
      currentNode = currentNode.next
    }
    return currentNode
  },
  // 往某一节点后面插入新节点
  insert: function(newItem, item){
    var newNode = new Node(newItem)
    var currentNode = this.find(item)
    if (currentNode.next !== null) {
      newNode.next = currentNode.next
      newNode.next.previous = newNode
      newNode.previous = currentNode
      currentNode.next = newNode
    } else {
      currentNode.next = newNode
      newNode.previous = currentNode
      newNode.next = null
    }
  },
  // 删除一个节点
  remove: function(item){
    var currentNode = this.find(item)
    if (currentNode.previous !== null && currentNode.next !== null) {  // 首先不是头尾节点的情况
      currentNode.previous.next = currentNode.next
      currentNode.next.previous = currentNode.previous
      currentNode.previous = null  // 如果不写,链表就会多出一条小分支
      currentNode.next = null  // 如果不写,链表就会多出一条小分支
    } else if (currentNode.previous === null) {  // 当是头节点的时候
      currentNode.next.previous = null
      currentNode.next = null
    } else if (currentNode.next === null) {  // 当是尾节点的时候
      currentNode.previous.next = null
      currentNode.previous = null
    }
  },
  // 找到最后一个节点
  findLast: function(){
    var currentNode = this.head
    while (currentNode.next !== null) {
      currentNode = currentNode.next
    }
    return currentNode
  },
  // 将要添加的节点放在链表末尾
  append: function(item){
    var lastNode = this.findLast()
    var newNode = new Node(item)
    lastNode.next = newNode
    newNode.previous = lastNode
    newNode.next = null
  },
  // 修改节点信息
  edit: function(item, newItem){
    // var currentNode = new Node(item)  // 这样会重新分配存储空间,改变不了链表的节点
    var currentNode = this.find(item)
    currentNode.element = newItem
  },
  // 打印链表所有节点
  display: function(){
    var currentNode = this.head
    while (currentNode.next !== null) {
      console.log(currentNode.next.element)
      currentNode = currentNode.next
    }
  },
  // 反向打印双链表的节点
  displayReverse: function(){
    var currentNode = this.findLast()
    while (currentNode.previous !== null) {
      console.log(currentNode.element)  // 这样其实是不会打印head的
      currentNode = currentNode.previous
    }
  },
}
测试:
const classify = new LinkedList()
classify.insert('human', 'head')
classify.insert('man', 'human')
classify.insert('shuaige', 'man')
classify.insert('nanshen', 'shuaige')
classify.display()
/*human
  man
  shuaige
  nanshen*/
console.log(classify.find('man'))  // {element: 'man', next: Node(下一个节点), previous: Node(上一个节点)}
classify.remove('nanshen')  // 删除“nanshen”节点
console.log(classify.findLast())  // {element: 'shuaige', next: null, previous: Node(上一个节点)}
classify.append('lvxiaobu')  // 往链表尾部插入“lvxiaobu”
classify.display()
/*human
  man
  shuaige
  lvxiaobu*/
classify.edit('lvxiaobu', 'huge')
classify.displayReverse()  // 反向打印链表
/*huge
  shuaige
  man
  human*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端吕小布

您的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值