目录
1、forwardString()(返回正向遍历的节点字符串形式)
2、backwardString() (返回反向遍历的节点字符串形式)
3、toString() (由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。)
双向链表结构
双向链表的封装
//封装双向链表
function DoublyLinkedList(){
// 封装一个内部类,可创建一个新节点
function Node(data){
this.data = data;
this.prev = null;
this.next = null;
}
// 属性
this.head = null;
this.tail = null;
this.length = 0;
}
一、追溯方法(append(data))
向双向链表尾部添加一个新的节点(该方法与单向链表的append方法类似)
1、创建新节点
// 1、创建新节点
var newNode = new Node(data);
2、判断双向链表的长度是否为0;
1.如果是,如图操作
this.head = newNode;
// 两种情况都需要的
this.tail = newNode;
2.如果不是为0,则是下面这种操作。
newNode.prev = this.tail;
this.tail.next = newNode;
// 两种情况都需要的
this.tail = newNode;
3、append方法代码:
DoublyLinkedList.prototype.append = function(data){
// 1、创建新节点
var newNode = new Node(data);
// 2、判断链表是否为空
if (this.length == 0) {//2.1 链表为空
this.head = newNode;
}else{//2.2 链表不为空
newNode.prev = this.tail;
this.tail.next = newNode;
}
// 两种情况都需要的
this.tail = newNode;
// 3、长度要加1
this.length += 1;
}
二、toString()的两种方式。
1、forwardString()(返回正向遍历的节点字符串形式)
DoublyLinkedList.prototype.forwardString = function(){
var current = this.head;
var resultString = '';
while(current){
resultString += current.data + ' ';
current = current.next;
}
return resultString;
}
2、backwardString() (返回反向遍历的节点字符串形式)
DoublyLinkedList.prototype.backwardString = function(){
var previous = this.tail;
var resultString = '';
while(previous){
resultString += previous.data + ' ';
previous = previous.prev;
}
return resultString;
}
3、toString() (由于列表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值。)
这里是正向遍历,所以直接调用forwardString()即可。
DoublyLinkedList.prototype.toString = function(){
return this.forwardString();
}
4、代码测试
// 测试代码
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
DLinkedList.append('a');
DLinkedList.append('b');
DLinkedList.append('c');
DLinkedList.append('d');
alert(DLinkedList.forwardString()); //a b c d
alert(DLinkedList.backwardString()); //d c b a
alert(DLinkedList.toString()); //a b c d
三、 inset(position, element)
向链表的特定位置插入一个新的节点。思路与单向链表的inset方法类似,具体操作如图所示。
1、当链表为空时。
// head和tail都指向newNode
this.head = newNode;
this.tail = newNode;
2、当链表不为空,插入的位置为0时。
newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;
3、当链表不为空,插入的位置是在表尾,与append的第二种方法相同(2.如果不是为0,则是下面这种操作。)
newNode.prev = this.tail;
this.tail.next = newNode;
// 两种情况都需要的
this.tail = newNode;
4、当链表不为空,插入的位置是在链表之中。
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
newNode.prev = current.prev; // 1
current.prev.next = newNode; // 2
newNode.next = current; // 3
current.prev = newNode; // 4
注意:这里需要注意的是,current所指向之前的节点(current.prev)和节点所带的next指向(current.prev.next)是新节点需要定位的节点,所以在改变current.prev的指向之前需要先执行①和②的操作。
5、链表长度加1
this.length += 1;
6、代码实现
DoublyLinkedList.prototype.inset = function(position, data){
// 1、 先判断position是否合法
if (position < 0 || position > this.length) return false;
// 2、创建新节点
var newNode = new Node(data);
// 3、 判断链表长度是否为0
if (this.length == 0) { // 3.1 链表长度为0
// head和tail都指向newNode
this.head = newNode;
this.tail = newNode;
}else{ // 3.2链表长度为0
// 4、 判断插入位置是否为0
if (position == 0) { // 4.1 插入位置为0
newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;
}else if(position == this.length){// 4.2插入位置为链表末尾
newNode.prev = this.tail;
this.tail.next = newNode;
}else{ // 4.3 插入位置在链表之中
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
newNode.prev = current.prev;
current.prev.next = newNode;
newNode.next = current;
current.prev = newNode;
}
}
// 5、长度要加1
this.length += 1;
}
7、代码检验
// 测试代码
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
DLinkedList.append('a');
DLinkedList.append('b');
DLinkedList.append('c');
DLinkedList.append('d');
alert(DLinkedList.toString()); //a b c d
DLinkedList.inset(0,'e');
alert(DLinkedList.toString()); //e a b c d
DLinkedList.inset(2,'f');
alert(DLinkedList.toString()); //e a f b c d
DLinkedList.inset(6,'g');
alert(DLinkedList.toString()); //e a f b c d g
四、get(position)
获取对应位置的元素
1.方法一(对于多元素的获取效率非常低)
DoublyLinkedList.prototype.get =function(position){
// 1、 先判断position是否合法
if (position < 0 || position > this.length - 1) return null;
// 2、根据position位置信息找到对应节点
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
return current.data;
}
2、方法二(利用双向列表的双向性)
DoublyLinkedList.prototype.getFast =function(position){
// 1、 先判断position是否合法
if (position < 0 || position > this.length - 1) return null;
// 2、根据position位置信息找到对应节点
var previous = this.head;
var current = this.tail;
if (position < this.length / 2) { //从前往后遍历
var index = 0;
while(index++ < position){
previous = previous.next;
}
return previous.data;
}else{ // 从后往前遍历
var index = this.length - 1;
while(index-- > position){
current = current.prev;
}
return current.data;
}
}
3、代码检验
// 测试代码
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
DLinkedList.append('a');
DLinkedList.append('b');
DLinkedList.append('c');
DLinkedList.append('d');
DLinkedList.append('e');
alert(DLinkedList.getFast(-1)); //null
alert(DLinkedList.getFast(0)); //a
alert(DLinkedList.getFast(1)); //b
alert(DLinkedList.getFast(2)); //c
alert(DLinkedList.getFast(3)); //d
alert(DLinkedList.getFast(4)); //e
alert(DLinkedList.getFast(5)); //null
五、indexOf(data)
返回元素在列表中的索引,如果列表中没有该元素则返回-1
DoublyLinkedList.prototype.indexOf =function(data){
var index = 0;
var current = this.head;
while(current){
if (current.data == data) return index;
current = current.next;
index += 1;
}
return -1;
}
2、测试代码
// 测试代码
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
DLinkedList.append('a');
DLinkedList.append('b');
DLinkedList.append('c');
alert(DLinkedList.indexOf('a')); //0
alert(DLinkedList.indexOf('b')); //1
alert(DLinkedList.indexOf('c')); //2
alert(DLinkedList.indexOf('d')); //-1
alert(DLinkedList.indexOf('e')); //-1
六、upDate
修改某位置的元素
方法一:(与get方法情况类似,可改进)
DoublyLinkedList.prototype.upDate = function(position, data){
// 越界判断
if (position < 0 || position >= this.length) return false;
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
current.data = data;
return true;
}
方法二:(改进后)
DoublyLinkedList.prototype.upDate = function(position, data){
// 越界判断
if (position < 0 || position >= this.length) return false;
// 2、根据position位置信息找到对应节点
var previous = this.head;
var current = this.tail;
if (position < this.length / 2) { //从前往后遍历
var index = 0;
while(index++ < position){
previous = previous.next;
}
previous.data = data;
}else{ //从后往前遍历
var index = this.length - 1;
while(index-- > position){
current = current.prev;
}
current.data = data;
}
return true;
}
七、removeAt(position)
删除相应位置的元素,如果删除成功返回其值
情况一:当链表的长度为1
this.head = null;
this.tail = null;
情况二:链表长度不为1,删除第一个节点。
this.head.next.prev = null
this.head = this.head.next;
情况三:链表长度不为1,删除最后一个节点。
this.tail.prev.next = null;
this.tail = this.tail.prev;
情况二:链表长度不为1,删除的节点不是第一个和最后一个。
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
current.prev.next = current.next;
current.next.prev = current.prev;
最后别忘记length-1
完整代码
DoublyLinkedList.prototype.removeAt = function(position){
// 判断position是否合法
if (position < 0 || position >= this.length) return false;
// 寻找节点
var current = this.head;
if (this.length == 1) {
this.head = null;
this.tail = null;
}else{
if (position == 0) {
// 让head指向第二个节点
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
this.length -= 1;
return current.data;
}
测试代码
// 测试代码
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
DLinkedList.append('a');
DLinkedList.append('b');
DLinkedList.append('c');
DLinkedList.removeAt(3);
alert(DLinkedList.toString()); //a b c
DLinkedList.removeAt(0);
alert(DLinkedList.toString()); //b c
DLinkedList.removeAt(1);
alert(DLinkedList.toString()); //b
DLinkedList.removeAt(0);
alert(DLinkedList.toString()); //
八、remove(element)
删除一项数据
DoublyLinkedList.prototype.remove = function(data){
// 根据data获取元素位置
var index = this.indexOf(data);
// 根据index将对应节点删除
return this.removeAt(index);
}
这里删除的是indexOf遍历时满足的第一个节点,后续不再查找。
九、判断链表是否为空
DoublyLinkedList.prototype.isEmpty = function(){
return this.length === 0;
}
十、返回链表的长度
DoublyLinkedList.prototype.size = function(){
return this.length;
}
十一、完整代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>双向链表的封装</title>
</head>
<body>
<script type="text/javascript">
//封装双向链表
function DoublyLinkedList(){
// 封装一个内部类,可创建一个新节点
function Node(data){
this.data = data;
this.prev = null;
this.next = null;
}
// 属性
this.head = null;
this.tail = null;
this.length = 0;
// 一、append方法:
DoublyLinkedList.prototype.append = function(data){
// 1、创建新节点
var newNode = new Node(data);
// 2、判断链表是否为空
if (this.length == 0) {//2.1链表为空
this.head = newNode;
}else{//2.2 链表不为空
newNode.prev = this.tail;
this.tail.next = newNode;
}
// 两种情况都需要的
this.tail = newNode;
// 3、长度要加1
this.length += 1;
}
// 二、两种toString方法
// 2.1forwardString
DoublyLinkedList.prototype.forwardString = function(){
var current = this.head;
var resultString = '';
while(current){
resultString += current.data + ' ';
current = current.next;
}
return resultString;
}
// 2.2 backwardString
DoublyLinkedList.prototype.backwardString = function(){
var previous = this.tail;
var resultString = '';
while(previous){
resultString += previous.data + ' ';
previous = previous.prev;
}
return resultString;
}
// 2.3 toString
DoublyLinkedList.prototype.toString = function(){
return this.forwardString();
}
// 三、 inset()
DoublyLinkedList.prototype.inset = function(position, data){
// 1、 先判断position是否合法
if (position < 0 || position > this.length) return false;
// 2、创建新节点
var newNode = new Node(data);
// 3、 判断链表长度是否为0
if (this.length == 0) { // 3.1 链表长度为0
// head和tail都指向newNode
this.head = newNode;
this.tail = newNode;
}else{ // 3.2链表长度为0
// 4、 判断插入位置是否为0
if (position == 0) { // 4.1 插入位置为0
newNode.next = this.head;
this.head.prev = newNode;
this.head = newNode;
}else if(position == this.length){// 4.2插入位置为链表末尾
newNode.prev = this.tail;
this.tail.next = newNode;
}else{ // 4.3 插入位置在链表之中
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
newNode.prev = current.prev;
current.prev.next = newNode;
newNode.next = current;
current.prev = newNode;
}
}
// 5、长度要加1
this.length += 1;
}
// 四、get()
// 方法一
DoublyLinkedList.prototype.get =function(position){
// 1、 先判断position是否合法
if (position < 0 || position > this.length - 1) return null;
// 2、根据position位置信息找到对应节点
var index = 0;
var current = this.head;
while(index++ < position){
current = current.next;
}
return current.data;
}
// 方法二(优化)
DoublyLinkedList.prototype.getFast =function(position){
// 1、 先判断position是否合法
if (position < 0 || position > this.length - 1) return null;
// 2、根据position位置信息找到对应节点
var previous = this.head;
var current = this.tail;
if (position < this.length / 2) {
var index = 0;
while(index++ < position){
previous = previous.next;
}
return previous.data;
}else{
var index = this.length - 1;
while(index-- > position){
current = current.prev;
}
return current.data;
}
}
// 五、
DoublyLinkedList.prototype.indexOf =function(data){
var index = 0;
var current = this.head;
while(current){
if (current.data == data) return index;
current = current.next;
index += 1;
}
return -1;
}
// 六
DoublyLinkedList.prototype.upDate = function(position, data){
// 越界判断
if (position < 0 || position >= this.length) return false;
// 2、根据position位置信息找到对应节点
var previous = this.head;
var current = this.tail;
if (position < this.length / 2) {
var index = 0;
while(index++ < position){
previous = previous.next;
}
previous.data = data;
}else{
var index = this.length - 1;
while(index-- > position){
current = current.prev;
}
current.data = data;
}
return true;
}
// 七
DoublyLinkedList.prototype.removeAt = function(position){
// 判断position是否合法
if (position < 0 || position >= this.length) return false;
// 寻找节点
var current = this.head;
if (this.length == 1) {
this.head = null;
this.tail = null;
}else{
if (position == 0) {
// 让head指向第二个节点
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
this.length -= 1;
return current.data;
}
// 八、remove(data)
DoublyLinkedList.prototype.remove = function(data){
// 根据data获取元素位置
var index = this.indexOf(data);
// 根据index将对应节点删除
return this.removeAt(index);
}
// 九、判断链表是否为空
DoublyLinkedList.prototype.isEmpty = function(){
return this.length == 0;
}
// 十、获取队列中的元素个数
DoublyLinkedList.prototype.size = function(){
return this.length;
}
}
// 创建DoublyLinkedList
var DLinkedList = new DoublyLinkedList();
// 测试代码
</script>
</body>
</html>