一.单向链表的缺点
在单向链表中,可以轻松的从头遍历到尾部,到达下一个节点,但是想回到前一个节点是很难的。
二.双向链表
- 既可以从头遍历到尾,又可以从尾遍历到头
- 链表相连的过程是双向的
- 一个节点既有向前连接的引用,也有一个向后连接的引用
- 双向链表可以解决单向链表的缺点
三.双向链表的缺点
- 每次在插入或删除某个节点时,需要处理四个引用,而不是两个,实现起来相对困难
- 与单向链表相比,占用内存空间更大
四.双向链表的特点
- 使用一个head和一个tail分别指向头部和尾部节点
- 每个节点都由三部分组成:前一个节点的指针(prev),保存的元素(item),后一个节点的指针(next)
- 双向链表的第一个节点的prev为null
- 双向链表的最后的节点的next为null
五.封装双向链表
function DoublyLinkedList(){
// 内部类:节点类
function Node(data){
this.data = data
this.prev = null
this.next = null
}
// 属性
this.head = null
this.tail = null
this.height = 0
}
六.双向链表的基本操作
- append方法:在链表的尾部插入节点
DoublyLinkedList.prototype.append = function(data){
var newNode = new Node(data)
if(this.length == 0){
this.head = newNode
}else{
var current = this.head
while(current.next){
current = current.next
}
current.next = newNode
}
this.length += 1
}
- 链表转换成字符串:forwardString方法和backwardString方法
//forwardString方法
DoublyLinkedList.prototype.forwardString = function(){
var current = this.head
var resultString = ''
// 依次向前遍历,获取每一个节点
while(current){
resultString += current.data + ''
current = current.prev
}
return resultString
}
//backwardString方法
DoublyLinkedList.prototype.backwardString = function(){
var current = this.head
var resultString = ''
// 依次向后遍历,获取每一个节点
while(current){
resultString += current.data + ''
current = current.next
}
return resultString
}
- insert方法:给定位置插入节点
DoublyLinkedList.prototype.insert = function(position,data){
// 越界判断
if(position < 0 || position > this.length) return false
// 根据data创建新节点
var newNode = new Node(data)
// 判断原来的链表是否为空
if(this.length == 0){
this.head = newNode
this.tail = newNode
}else{
// 1.判断position是否为0
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{
// 节点插入在中间位置
var current = this.head
var index = 0
while(index++ < position){
current = current.next
}
newNode.next = current
newNode.prev = current.prev
current.prev.next = newNode
current.prev = newNode
}
this.length += 1
return true
}
}
- get方法:获取给定位置的数据
// 方法1(普通方法)
DoublyLinkedList.prototype.get = function(position){
// 越界判断
if(position < 0 || position >= this.length) return false
// 获取元素
var current = this.head
var index = 0
while(index++ < position){
current = current.next
}
return current.data
}
// 方法2
DoublyLinkedList.prototype.get = function(position){
// 越界判断
// this.length / 2 > position: 从头向后遍历
// this.length / 2 < position: 从后向前遍历
// 从后向前遍历的操作:
var current = this.tail
var index = this.length - 1 // 链表的长度-1
while(index-- > position){
current = current.prev
}
return current.data
}
- indexOf方法:返回元素在链表中的索引,若链表中没有该元素则返回-1
DoublyLinkedList.prototype.indexOf = function(data){
// 定义变量
var current = this.head
var index = 0
// 查找和data相同的节点
while(current){
if(current.data == data){
return index
}else{
current = current.next
index++
}
}
return -1
}
- update方法:修改数据元素
DoublyLinkedList.prototype.update = function(position,newData){
// 越界判断
if(position < 0 || position >= this.length) return false
// 修改元素
var current = this.head
var index = 0
while(index++ < position){
current = current.next
}
current.data = newData
return true
}
- removeAt方法:删除链表中的节点
DoublyLinkedList.prototype.removeAt = function(position){
//越界判断
if(position < 0 || position >= this.length) return null
//判断是否只有一个节点
var current = this.head
if(this.length == 1){
this.head = null
this.tail = null
}else{
// 判断是否删除的是第一个节点
if(position == 0){
this.head.next.prev = null
this.head = this.head.next
}
}else if(position == this.length - 1){
// 删除最后一个节点
current = this.tail
this.tail.prev.next = null
this.tail = this.tail.prev
}else{
var index = 0
while(index++ < position){
current = current.next
}
current.prev.next = current.next
current.next.prev = current.prev
}
length -= 1
return current.data
}
- remove方法:给定具体数据,删除链表中对应的节点
DoublyLinkedList.prototype.remove = function(data){
// 根据data获取下标值
var index = this.indexOf(data)
// 根据index删除对应位置的节点
return this.removeAt(index)
}
- isEmpty方法:判断链表是否为空
DoublyLinkedList.prototype.isEmpty = function(){
return this.length == 0
}
- size方法
DoublyLinkedList.prototype.size = function(){
return this.length
}
- getHead方法:获取链表的第一个元素
DoublyLinkedList.prototype.getHead = function(){
return this.head.data
}
- getTail方法:获取链表的最后一个元素
DoublyLinkedList.prototype.getTail = function(){
return this.tail.data
}