JS 双链表的概念与实现

21 阅读1分钟

1. 概念

双链表,每个数据节点中有两个指针,分别指向前驱后继

2. 特点

  • header tail 指向头尾;
  • 由三个部分组成(头、尾、元素);
  • 第一个节点前驱为 null
  • 最后一个节点的后继为 null

3. 常用方法

  • append(ele) -尾部插入;
  • insert(position,ele) - 特定位置插入;
  • update(position,ele) - 更新特定位置;
  • removeAt(position) - 删除位置上的某一项;
  • remove(ele) - 删除某一个元素;
  • isEmpty() - 判断链表是否为空;
  • size() - 返回链表中的数据长度;
  • tostring() - 打印链表中的数据;

4. 双链表实现

function DoubleList() {
  // 构建数据
  function Node(data) {
    this.prev = null
    this.data = data
    this.next = null
  }
  // 外层标识
  this.head = null
  this.tail = null
  this.length = 0
  // 尾部添加方法
  DoubleList.prototype.append = (data) => {
    let newNode = new Node(data)
    if (this.length == 0) {
      this.head = newNode
      this.tail = newNode
      newNode.prev = null
    } else {
      // 改变指向
      this.tail.next = newNode
      newNode.prev = this.tail
      this.tail = newNode
    }

    this.length++
  }

  DoubleList.prototype.insert = (position, dada) => {
    if (position < 0 || position > this.length) {
      return false
    } else {
      if (position == 0) {
        this.head.prev = newNode
        newNode.next = this.head;
        this.head = newNode
      } else if (position == this.length) {
        this.tail.next = newNode
        newNode.prev = this.tail
        this.tail = newNode
      } else {
        let current = this.head
        let index = 0
        while (index < position) {
          current = current.next
          index++
        }
        current.prev.next = newNode
        newNode.prev = current.prev
        newNode.next = current
        current.prev = newNode
      }
    }
    this.length++
  }

  DoubleList.prototype.update = (position, data) => {
    if (position < 0 || position > this.length) {
      return false
    }

    let current = this.head
    let index = 0
    while (index < position) {
      current = current.next
      index++
    }
    current.data = data
    return true
  }

  DoubleList.prototype.removeAt = (position) => {
    if (position < 0 || position > this.length) {
      return false
    }
    if (this.length == 1) {
      this.head = null
      this.tail = null
    } else {
      if (position == 0) {
        this.head = this.head.next
        this.head.prev = null
      } else if (position == this.length) {
        this.tail = this.tail.prev
        this.tail.next = null
      } else {
        let current = this.head
        let index = 0
        while (index < position) {
          current = current.next
          index++
        }
        current.prev.next = current.next
        current.next.prev = current.prev
      }
    }
    this.length--
    return true
  }

  DoubleList.prototype.remove = (data) => {
    let current = this.head
    let index = 0
    while (current.data != data) {
      current = current.next
      index++
    }
    return this.removeAt(index)
  }

  DoubleList.prototype.isEmpty = () => {
    return !this.length
  }

  DoubleList.prototype.size = () => {
    return this.length
  }

  DoubleList.prototype.tostring = () => {
    let current = this.head
    let str = []
    while (current) {
      str += current.data + '\n'
      current = current.next
    }
    return str
  }
}

var list = new DoubleList();
list.append('1');
list.append('2');
list.append('3');
list.append('4');
list.append('5');
list.append('6');
list.update(3, '7')
console.log(list.size())
console.log(list.remove(2))
console.log(list.removeAt(3))
console.log(list.isEmpty());
console.log(list);

拓展 手写一个indexOf方法便于查找元素在链表中的位置

// 方式一
  DoubleList.prototype.remove = (data) => {
    let current = this.head
    let index = 0
    while (current.data != data) {
      current = current.next
      index++
    }
    return this.removeAt(index)
  }
  
// 方式二
  DoubleList.prototype.indexOf = (element) => {
    let currentNode = this.head
    let index = 0
    while (index < this.length) {
      if (currentNode.data === element) {
        break;
      }
      currentNode = currentNode.next
      index++
    }
    return index === this.length ? -1 : index
  }

  DoubleList.prototype.remove = (data) => {
    return this.removeAt(this.indexOf(data))
  }