链表对应生活中的例子: 火车(一节带动一节, 必要时可以拆卸或添加一节车厢)
链表通过指针连接, 如果需要插入或删除只需改变相应指针指向的目标就行。这也是链表相比较于数组最大的优点, 不用移动元素就能很轻松地添加删除元素。如果有大量的数据要插入或删除可以考虑使用链表这种数据结构。
var LinkedList = function() {const Node = function(element) {this.element = elementthis.next = null}let head = nulllet currentlet length = 0// 在链表末尾加入元素this.append = function(element) {const node = new Node(element)if (head === null) { // 插入第一个链表head = node} else {current = headwhile (current.next) { // 找到最后一个节点current = current.next}current.next = node}length++}// 移除指定位置元素this.removeAt = function(position) {if (position > -1 && position < length) {let previouslet index = 0if (position === 0) { // 如果是第一个链表的话, 特殊对待head = head.next} else {current = headwhile (index < position) { // 循环找到当前要删除元素的位置previous = currentcurrent = current.nextindex++}previous.next = current.next}length--}}// 在指定位置加入元素this.insert = function(position, element) {const node = new Node(element)let index = 0let current, previousif (position > -1 && position < length + 1) {if (position === 0) { // 在链表最前插入元素current = headhead = nodehead.next = current} else {current = headwhile (index < position) { // 同 removeAt 逻辑, 找到目标位置previous = currentcurrent = current.nextindex++}previous.next = node // 在目标位置插入相应元素node.next = current}length++}}// 链表中是否含有某个元素, 如果有的话返回相应位置, 无的话返回 -1this.indexOf = function(element) {let index = 0current = headwhile (index < length) {if (current.element === element) {return index}current = current.nextindex++}return -1}// 移除某元素this.remove = function(element) {const position = this.indexOf(element)this.removeAt(position)}// 获取大小this.size = function() {return length}// 获取最开头的链表this.getHead = function() {return head}// 是否为空this.isEmpty = function() {return length === 0}// 打印链表元素this.log = function() {current = headlet str = current.elementwhile (current.next) {current = current.nextstr = str + ' ' + current.element}return str}}// 测试用例var linkedList = new LinkedList()linkedList.append(5)linkedList.append(10)linkedList.append(15)linkedList.append(20)linkedList.log() // '5 10 15 20'linkedList.removeAt(1)linkedList.log() // '5 15 20'linkedList.insert(1, 10)linkedList.log()
单向链表如果错过了某次查询就得重头开始重新查找, 双向链表进行了升级, 除了可以向后查找, 同时也支持向前查找
var DbLinkedList = function() {const Node = function(element) {this.element = elementthis.next = nullthis.prev = null}let head = nulllet tail = nulllet current, previouslet length = 0// 指定任意位置插入元素this.insert = function(position, element) {let index = 0const node = new Node(element)if (position > -1 && position < length + 1) {if (position === 0) { // ① 在开头插入元素if (head === null) { // 链表内元素为空head = nodetail = node} else { // 链表内存在元素current = headhead = nodehead.next = currentcurrent.prev = head}} else if (position === length) { // ② 在末尾插入元素current = tailtail = nodecurrent.next = tailtail.prev = current} else { // ③ 在链表中插入元素current = headwhile (index < position) { // 找到需插入节点的位置previous = currentcurrent = current.nextindex++}previous.next = nodenode.next = currentcurrent.prev = nodenode.prev = previous}length++}}// 删除指定位置的元素this.removeAt = function(position) {let index = 0if (position > -1 && position < length) {if (position === 0) { // 删除链表最开头的元素if (length === 1) {head = nulltail = null} else {current = headhead = current.nexthead.prev = current.prev}} else if (position === length - 1) { // 删除链表最末尾的元素current = tailtail = current.prevtail.next = current.next} else { // 删除链表中的元素current = headwhile (index < position) {previous = currentcurrent = current.nextindex++}previous.next = current.nextcurrent.next.prev = previous}length--}}this.log = function() {current = headlet str = current.elementwhile (current.next) {current = current.nextstr = str + ' ' + current.element}return str}}var dbLinkedList = new DbLinkedList()dbLinkedList.insert(0, 5)dbLinkedList.insert(1, 10)dbLinkedList.insert(2, 15)dbLinkedList.insert(3, 20)dbLinkedList.insert(4, 25)dbLinkedList.log() // "5 10 15 20 25"dbLinkedList.removeAt(4)dbLinkedList.removeAt(0)dbLinkedList.removeAt(1)dbLinkedList.log() // "10 20"
此外还有循环链表, 和上述代码类似, 在此省略。