线性结构_双向链表
双向链表
1. 单向链表的特点
1. 只能从头遍历到尾,或者从尾遍历到头(一般是从头到尾),即链表数单向的
2. 实现的原理是上一个节点中存储有下一个节点的引用
2. 单向链表存在的问题
1. 从一个节点到达下一个节点很容易,但是从下一个节点回到上一个节点无法实现
2. 而实际中,我们需要从某个节点嗲它的上一个节点。
如文本编辑中,通过前后箭头可以使得光标前后移动
3. 双向链表的特点
1. 既可以从头遍历到尾,也可以从尾遍历到头
2. 实现原理就是在每一个节点中,同时存储下一个节点的引用和上一个节点的引用
4. 双向链表的缺点
1. 占用内存空间更大,因为每个节点存储的数据变多了
2. 操作变得复杂,如每次在删除,添加节点时,需要改变四个引用的位置,而单向链表只需要改动两个
5. 双向链表的结构
1. 链表包含一个header指向头部,包含一个tail指向尾部
2. 每个节点由三部分组成:
指向前一个节点的指针(prev) --> 默认指向null
存储本节点数据的变量(item)
指向后一个节点的指针(next) --> 默认指向null
6. 双向链表的方法
1. appendItem(element) 向链表尾部添加一个新的项
2. insertItem(position, element) 向链表中的指定位置插入元素
3. getItem(position) 获取对应位置的元素
4. indexOf(element) 返回元素在列表中的索引,若没有则返回-1
5. update(position, element) 修改指定位置的值
6. removeAt(position) 从列表中移出指定位置的元素
7. remove(element) 从列表中移出指定值的元素
8. isEmpty() 判断链表是否为空
9. size() 返回链表的长度
10. forwardToString() 正向遍历链表,以字符串的形式返回链表元素
11. backwardToString() 反向遍历链表,以字符串的形式返回链表元素
7. 双向链表的代码实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
function DoubleList(){ // 定义双向链表中的节点对象 function Node(item){ this.prev = null; this.item = item; this.next = null; } // 双向链表中的属性 this.header = null; this.tail = null this.length = 0; // 双向链表中的方法 // 1. 向链表尾部添加一个新的项 DoubleList.prototype.appendItem = function(element){ // 1. 将新添加的元素转换成节点 var newNode = new Node(element); if(this.header == null){ // 2. 若原链表为空,则直接将链表头部指向新节点 this.header = newNode; }else{ // 3. 若原链表不为空,则进行如下操作 // 将头节点地址赋值给cur变量 cur = this.header; for(var i = 1; i < this.length; i++){ // 逐步查找 cur = cur.next; } // 此时已经查找到尾部 cur.next = newNode; newNode.prev = cur; } // 链表尾部指向最后一个节点 this.tail = newNode; this.length++; } // 2. 向链表中的指定位置插入元素 DoubleList.prototype.insertItem = function(position, element){ var newNode = new Node(element); if(position + 1 > this.length){ alert("所输入的位置超过链表长度,请重新输入"); }else if(position == 0){ this.header = newNode; this.tail = newNode; this.length++; }else{ var cur = this.header; for(var k = 0; k < this.length; k++){ if(k == position){ cur.prev.next = newNode; newNode.prev = cur.prev; cur.next.prev = newNode; newNode.next = cur; }else{ cur = cur.next; } } this.tail = newNode; this.length++; } } // 3. 获取对应位置的元素 DoubleList.prototype.getItem = function(position){ var cur = this.header; if(position + 1 > this.length){ alert("所输入的位置超过链表长度,请重新输入"); }else{ for(var i = 0; i < position; i++){ cur = cur.next; } return cur.item; } } // 4. 返回元素在列表中的索引,若没有则返回-1 DoubleList.prototype.indexOf = function(item){ var cur = this.header; var index = -1; for(var k = 0; k < this.length; k++){ if(cur.item == item){ index = k; break; } cur = cur.next } return index; } // 5. 修改指定位置的值 DoubleList.prototype.updata = function(position, element){ if(position + 1 > this.length){ alert("所输入的位置超过链表长度,请重新输入"); }else{ var cur = this.header; for(var i = 0; i < position; i++){ cur = cur.next; } cur.item = element; } } // 6. 从列表中移除指定位置的元素 DoubleList.prototype.removeAt = function(position){ if(position + 1 > this.length){ alert("所输入的位置超过链表长度,请重新输入"); }else{ var cur = this.header; for(var i = 1; i < position; i++){ cur = cur.next; } cur.next = cur.next.next; cur.next.next.prev = cur; this.length--; if(position == this.length -1){ this.tail = newNode; } } } // 7. 从列表中移出指定值的元素,返回值为删除元素的个数 DoubleList.prototype.remove = function(element){ var cur = this.header; var count = 0; for(var k = 0; k < this.length; k++){ if(cur.item == element){ cur.prev.next = cur.next; cur.next.prev = cur.prev; count++; } cur = cur.next; } this.length = this.length - count; if(k == this.length - 1){ this.tail = cur; } return count; } // 8. 判断链表是否为空 DoubleList.prototype.isEmpty = function(){ return this.length == 0; } // 9. 返回链表的长度 DoubleList.prototype.size = function(){ return this.length; } // 10. 正向遍历链表,以字符串的形式返回链表元素 DoubleList.prototype.forwardToString = function(){ var res = ""; var cur = this.header; for(var k = 0; k < this.length; k++){ res += cur.item + " "; cur = cur.next; } return res } // 11. 反向遍历链表,以字符串的形式返回链表元素 DoubleList.prototype.backwardToString = function(){ var res = ""; var cur = this.tail; for(var k = 0; k < this.length; k++){ res += cur.item + " "; cur = cur.prev; } return res } }