# 链表
链表存储有序的元素集合。
在大多数语言中,数组的大小是固定的,从数组的起点或中间插入或移除项的成本很高,因为需要移动元素。
不同于数组,链表中的元素在内存中并不是连续放置的。每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(也称指针或链接)组成。
# 链表的操作
append(element):向列表尾部添加一个新项insert(position, element):向列表的指定位置插入一个新项remove(element):从列表中移除一项removeAt(position):从列表的特定位置移除一项indexOf(element):返回元素在列表中的索引。如果列表中没有该元素则返回 -1getHead():返回当前头节点isEmpty(): 如果链表中不包含任何元素, 返回 true, 如果链表长度大于 0 则返回 falsesize():返回链表包含的元素个数print ():遍历整个链表
# 链表的实现
class Node {
  constructor(element) {
    this.element = element
    this.next = null
  }
}
class LinkedList {
  constructor() {
    this.length = 0
    this.head = null
  }
  append(element) {
    let current = this.head
    const node = new Node(element)
    if (!current) {
      this.head = node
    } else {
      while (current.next) {
        current = current.next
      }
      current.next = node
    }
    this.length++
  }
  toString() {
    let str = ''
    let current = this.head
    while (current) {
      str = str ? `${str} -> ${current.element}` : `${current.element}`
      current = current.next
    }
    return str
  }
  print() {
    console.log(this.toString())
  }
}
const ll = new LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.print() // 1 -> 2 -> 3 -> 4
insert 方法:
class LinkedList {
  // ...
  insert(position, element) {
    if (0 > position || position > this.length) {
      // 越界检查
      return
    }
    const node = new Node(element)
    let current = this.head,
      index = 0
    if (0 === position) {
      node.next = current
      this.head = node
    } else {
      while (++index < position) {
        current = current.next
      }
      node.next = current.next
      current.next = node
    }
    this.length++
  }
}
const ll = new LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.insert(0, 0)
ll.insert(2, 1.5)
ll.print() // 0 -> 1 -> 1.5 -> 2 -> 3 -> 4
removeAt 方法:
class LinkedList {
  removeAt(position) {
    if (0 > position || position >= this.length) {
      return
    }
    let current = this.head,
      previous = null,
      index = 0
    if (0 === position) {
      this.head = current.next
    } else {
      while (index++ < position) {
        previous = current
        current = current.next
      }
      previous.next = current.next
    }
    this.length--
    return current.element
  }
}
const ll = new LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.insert(0, 0)
ll.removeAt(3)
ll.print() // 0 -> 1 -> 2 -> 4
remove 方法:
class LinkedList {
  remove(element) {
    let current = this.head,
      previous = null
    if (current.element === element) {
      this.head = current.next
      this.length--
    } else {
      while (current) {
        if (current.element === element) {
          previous.next = current.next
          this.length--
          break
        } else {
          previous = current
          current = current.next
        }
      }
    }
    return current.element
  }
}
const ll = new LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.insert(0, 0)
ll.remove(2)
ll.print() // 0 -> 1 -> 3 -> 4
indexOf 方法:
class LinkedList {
  indexOf(element) {
    let index = 0,
      current = this.head
    while (current) {
      if (current.element === element) {
        return index
      } else {
        current = current.next
        index++
      }
    }
    return -1
  }
}
const ll = new LinkedList()
ll.append(1)
ll.append(2)
ll.append(3)
ll.append(4)
ll.insert(0, 0)
console.log(ll.indexOf(3)) // 3
其它方法:
class LinkedList {
  isEmpty() {
    return this.length === 0
  }
  size() {
    return this.length
  }
  getHead() {
    return this.head
  }
}
完整代码:
class LinkedList {
  constructor() {
    this.length = 0
    this.head = null
  }
  append(element) {
    let current = this.head
    const node = new Node(element)
    if (!current) {
      this.head = node
    } else {
      while (current.next) {
        current = current.next
      }
      current.next = node
    }
    this.length++
  }
  insert(position, element) {
    if (0 > position || position > this.length) {
      // 越界检查
      return
    }
    const node = new Node(element)
    let current = this.head,
      index = 0
    if (0 === position) {
      node.next = current
      this.head = node
    } else {
      while (++index < position) {
        current = current.next
      }
      node.next = current.next
      current.next = node
    }
    this.length++
  }
  remove(element) {
    let current = this.head,
      previous = null
    if (current.element === element) {
      this.head = current.next
      this.length--
    } else {
      while (current) {
        if (current.element === element) {
          previous.next = current.next
          this.length--
          break
        } else {
          previous = current
          current = current.next
        }
      }
    }
    return current.element
  }
  removeAt(position) {
    if (0 > position || position >= this.length) {
      return
    }
    let current = this.head,
      previous = null,
      index = 0
    if (0 === position) {
      this.head = current.next
    } else {
      while (index++ < position) {
        previous = current
        current = current.next
      }
      previous.next = current.next
    }
    this.length--
    return current.element
  }
  indexOf(element) {
    let index = 0,
      current = this.head
    while (current) {
      if (current.element === element) {
        return index
      } else {
        current = current.next
        index++
      }
    }
    return -1
  }
  isEmpty() {
    return this.length === 0
  }
  size() {
    return this.length
  }
  getHead() {
    return this.head
  }
  toString() {
    let str = ''
    let current = this.head
    while (current) {
      str = str ? `${str} -> ${current.element}` : `${current.element}`
      current = current.next
    }
    return str
  }
  print() {
    console.log(this.toString())
  }
}
← 641. 设计循环双端队列 双向链表 →