前面介绍了列表对数据排序,当时底层存储数据的数据结构是数组。这里将讨论另一种列表:链表,它的底层存储数据的数据结构是对象。javascript
数组不老是组织数据的最佳数据结构。由于java
若是数组在实际使用时很慢,就能够考虑使用链表来替代它。除了对数据的随机访问,链表能够用在任何能够使用一维数组的状况下。固然,若是须要随机访问,数组仍然是最优的选择。c++
链表是由一组节点组成的集合。每一个节点均可以使用一个对象的引用指向它的后继。指向另外一个节点的引用叫作:链。算法
在链表中插入一个节点的效率很高,向链表中插入一个节点,须要修改它前面的节点,使其指向新加入的节点,而新加入的节点则指向原来前驱指向的节点。编程
在链表中删除一个节点也很快,将待删除的元素的前驱节点指向待删除元素的后继节点,同时将待删除元素指向null,元素就删除成功了。数组
// Node类用来表示节点
function Node(element) {
this.element = element // element用来保存节点上的数据
this.next = null // next用来保存指向下一个节点的连接
}
// LinkedList类提供对链表进行操做的方法
function LinkedList() {
this.head = new Node('head')
}
LinkedList.prototype = {
constructor: LinkedList,
// 查找节点(遍历链表,查找给定数据)
find: function (item) {
var currNode = this.head
while (currNode.element !== item) {
currNode = currNode.next
}
return currNode
},
// 插入节点
insert: function (newElement, item) {
var newNode = new Node(newElement)
var current = this.find(item) // 找到插入节点的位置
newNode.next = current.next // 将新节点的next属性设置未‘后’节点的next属性对应的值
current.next = newNode // 设置‘后’节点的next属性指向新节点
},
// 查找要删除节点的前一个节点
findPrev: function (item) {
var currNode = this.head
while (!(currNode.next === null) && (currNode.next.element !== item)) {
currNode = currNode.next
}
return currNode
},
// 删除节点
remove: function (item) {
var prevNode = this.findPrev(item)
if (!(prevNode.next === null)) {
prevNode.next = prevNode.next.next // 让前一个节点指向了待删除节点的后一个节点
}
},
// 显示链表中的元素
dispaly: function () {
var currNode = this.head
while (!(currNode.next === null)) {
console.log(currNode.next.element)
currNode = currNode.next
}
}
}
// 使用
var people = new LinkedList()
people.insert('wu', 'head')
people.insert('qin', 'wu')
people.insert('hao', 'qin')
people.insert('is', 'hao')
people.insert('a', 'is')
people.insert('good', 'a')
people.insert('boy', 'good')
people.dispaly()
console.log('-------------------------------------')
people.remove('good')
people.dispaly()
复制代码
若是算法中须要频繁地找某结点的前趋结点,单链表的解决方式是遍历整个链表,增长算法的时间复杂度,影响总体效率。数据结构
为了快速便捷地解决这类问题,在单向链表的基础上,给各个结点额外配备一个指针变量,用于指向每一个结点的直接前趋元素。这样的链表被称为“双向链表”或者“双链表”。编程语言
双向链表中的结点有两个指针域,一个指向直接前趋,一个指向直接后继。(链表中第一个结点的前趋结点为NULL,最后一个结点的后继结点为NULL)ui
// Node类用来表示节点
function Node(element) {
this.element = element // element用来保存节点上的数据
this.next = null // next用来保存指向下一个节点的连接
this.previous = null // previous用来保存指向上一个节点的连接
}
// LinkedListBoth类提供对双向链表进行操做的方法
function LinkedListBoth() {
this.head = new Node('head')
}
LinkedListBoth.prototype = {
constructor: LinkedListBoth,
// 查找节点(遍历链表,查找给定数据)
find: function (item) {
var currNode = this.head
while (currNode.element !== item) {
currNode = currNode.next
}
return currNode
},
// 插入节点
insert: function (newElement, item) {
var newNode = new Node(newElement)
var current = this.find(item) // 找到插入节点的位置
newNode.next = current.next // 将新节点的next属性设置未‘后’节点的next属性对应的值
newNode.previous = current
current.next = newNode // 设置‘后’节点的next属性指向新节点
},
// 查找要删除节点的前一个节点
//findPrev: function (item) {
// var currNode = this.head
// while (!(currNode.next === null) && (currNode.next.element !== item)) {
// currNode = currNode.next
// }
// return currNode
//},
// 删除节点
remove: function (item) {
var currNode = this.find(item)
if (!(currNode.next === null)) {
currNode.previous.next = currNode.next
currNode.next.previous = currNode.previous
currNode.next = null
currNode.previous = null
}
},
// 显示链表中的元素
dispaly: function () {
var currNode = this.head
while (!(currNode.next === null)) {
console.log(currNode.next.element)
currNode = currNode.next
}
},
// 查找最后节点
findLast: function () {
var currNode = this.head
while (!(currNode.next === null)) {
currNode = currNode.next
}
return currNode
},
// 反序显示双向链表中的元素
dispReverse: function () {
var currNode = this.head
currNode = this.findLast()
while (!(currNode.previous === null)) {
console.log(currNode.element)
currNode = currNode.previous
}
}
}
// 使用
var people = new LinkedListBoth()
people.insert('wu', 'head')
people.insert('qin', 'wu')
people.insert('hao', 'qin')
people.insert('is', 'hao')
people.insert('a', 'is')
people.insert('good', 'a')
people.insert('boy', 'good')
people.dispaly()
console.log('-------------------------------------')
people.remove('good')
people.dispaly()
console.log('-------------------------------------')
people.dispReverse()
复制代码
若是你但愿能够从后向前遍历列表,可是又不想付出额外表明来建立一个双向列表,那么就须要使用循环链表。从循环链表的尾节点向后移动,就等于从后向前遍历链表。this