其实无论在任何语言中,一种数据结构往往会有很多的延伸和变种以应对不同场景的需要。其实前面我们所学过的栈和队列也是可以用链表来实现的。有兴趣的小伙伴可以自己尝试着去实现以下。

  有点跑题了...,我们还是说回链表,在基础链表之外,还有双向链表和循环链表和双向循环链表。这篇文章会详细的介绍一下双向链表,但是不会详细的去讲解循环链表。因为其实真的没有太大的区别。链表和循环链表的唯一的区别在于,最后一个元素指向下一个元素的指针不是null,而是head。

  其实循环链表只能从头到尾的循环,而双向循环链表可以两个方向循环,想怎么玩怎么玩。

  嗯...又跑题了,我们还是来说双向链表吧。

  顾名思义...双向链表就是....双向链表!额...开个玩笑...咱们进入正题吧....

  其实简单说双向链表与链表的区别就在于,双向链表不仅仅有一个指向下一个节点元素的指针,还同时拥有一个指向上一个节点元素的指针。前后都可以链接,故,称之为双向链表。

  那么既然是双向的指针,所以我们的代码需要新增一些东西。

  由于双向链表内的一些方法与链表无异,所以这里只说明一下那些区别明显有重要意义的地方。不再贴上所有的代码。

function DoublyLinkedList() {
let Node = function (element) {
this.element = element;
this.next = null;
//在双向链表中,这里多了个指向前一个节点元素的指针prev
this.prev = null;
} let length = 0;
let head = null;
//同样的这里多了一个保存链表最后一项节点的引用变量,为什么要加这个变量?
//因为是双向链表,普通链表只能从头到尾的迭代各节点元素,一方面是因为普通链表中只有一个存储头部节点元素的head变量。
//但是双向链表可以从尾部开始迭代,这就是tail的意义。
let tail = null;
}

  这就是双向链表的类的变动(不包括其中的方法),我们可以看到只是多了node节点元素中prev(前一个)节点元素的指针,还有tail变量对尾部节点元素的引用。

  那么下面我们来看看insert方法的变化。

//我们来看看双向链表中insert方法,普通链表中,我们只需要控制next指针就可以了,但是在双向链表中,在控制next指针的同时,我们还要控制prev指针
this.insert = function (position,element) {
//在普通链表中在任意位置添加元素有两种情况,一个是添加到头部,另外一个是除了头部以外的其他位置,
//在双向链表中除了这两种情况,还多了一种,添加在链表尾部
if(position >= 0 && position <= length) {
let node = new Node(element);
let current = head;
let previous;
let index = 0;
//添加到头部的情况
if(position === 0) {
//这里,如果head为null,也就是说该链表是没有任何节点元素的情况,那么加入的这个节点元素在链表中是唯一的
//所以,head引用为node,tail的引用也为node
if(!head) {
head = node;
tail = node;
//那么如果,head不为null,说明链表中存在至少一个元素。
} else {
//由于current就是head,那么要插入节点元素的话只要把node的next指针指向current,就说明我们在current前面插入了该节点元素。
node.next = current;
//因为是双向列表,我们还要给current.prev一个指向。
current.prev = node;
//那么既然我们在current前面插入了元素,这里也就要改变head的引用,变为我们插入的node
head = node;
}
//如果我们想要插入尾部的情况
} else if(position === length) {
//这里稍微有趣一点,这里我们要在尾部加入元素,不用像普通链表那样迭代到最后一项再操作。
//我们只需要把current直接置为tail的引用就可以了,方便快捷
current = tail;
//那么我们已经拿到了最后一项节点元素的引用并且设置为了current。
//我们只需要把current(tail)的next指向node节点元素,并且把node的prev只想current。
//其实就是说,current节点的next指针不再是null了,因为我们在它的后面增加了一个“插入元素”,所以它的next指针为node
//而此时node的prev指针也就理所当然的指向了current。
current.next = node;
node.prev = current;
//插入元素完成,但是我们此时的tail其实是current不是node,所以更改一下tail的引用。
tail = node;
} else {
while(index++ < position) {
//依次往后移动...不多说
previous = current;
current = current.next;
}
//在移动到需要插入节点元素的位置时。
//我们要插入在current的前面,自然就会有下面的结果了
node.next = current;
previous.next = node;
//但是我们由于是双向链表,我们不仅仅要修改next指针,还要修改prev指针
current.prev = node;
node.prev = previous;
}
length++;
return true;
} else {
return false;
}
}

  其实insert方法在双向链表中,只是多了一种尾部情况的判断以及prev指针的改变,注释已经说的很详细了,不多说废话,我们继续看看removeAt方法在双向链表中的实现。

this.removeAt = function (position) {
if(position > -1 && position < length) {
let current = head,previous,index = 0; if(position === 0) {
head = current.next;
if(length === 1) {
tail = null
} else {
head.prev = null;
}
} else if(position === length - 1) {
current = tail;
tail = current.prev;
tail.next = null;
} else {
while(index++ < position) {
previous = current;
current = current.next;
} previous.next = current.next;
current.next.prev = previous;
} length --;
return current.element;
} else {
return null;
}
}

  这是双向链表的removeAt方法,我不想解释了,因为我觉得如果你认真的阅读了这两篇文章,这个方法你绝对可以看懂了。如果你还是看不懂,请从头再来

  这里我们就基本介绍完了双向链表...等等...不是还有其它的方法么?怎么不说了?

  insert可以在任意位置插入元素,removeAt可以在任意位置移除元素,想要实现其它方法就不难了吧。。。。。再说下去也是重复前面说过的内容了。实在无须如此....

  那么我们对于链表的了解就告一段落,下一篇文章我们一起来看看集合这个东东。感觉会比链表好玩一些。嗯...对,跟数学中的集合有关系。

  

  最后,由于本人水平有限,能力与大神仍相差甚远,若有错误或不明之处,还望大家不吝赐教指正。非常感谢!

用js来实现那些数据结构08(链表02-双向链表)的更多相关文章

  1. 用js来实现那些数据结构—目录

    首先,有一点要声明,下面所有文章的所有内容的代码,都不是我一个人独立完成的,它们来自于一本叫做<学习JavaScript数据结构和算法>(第二版),人民邮电出版社出版的这本书.github ...

  2. 用js来实现那些数据结构及算法—目录

    首先,有一点要声明,下面所有文章的所有内容的代码,都不是我一个人独立完成的,它们来自于一本叫做<学习JavaScript数据结构和算法>(第二版),人民邮电出版社出版的这本书.github ...

  3. 用js来实现那些数据结构07(链表01-链表的实现)

    前面讲解了数组,栈和队列.其实大家回想一下.它们有很多相似的地方.甚至栈和队列这两种数据结构在js中的实现方式也都是基于数组.无论增删的方式.遵循的原则如何,它们都是有序集合的列表.在js中,我们新建 ...

  4. (js描述的)数据结构 [数组的一些补充](1)

    (js描述的)数据结构 [数组的一些补充](1) 1. js的数组: 1.优点:高度封装,对于数组的操作就是调用API 2.普通语言的数组: 1.优点:根据index来查询,修改数据效率很高 2.缺点 ...

  5. 学习javascript数据结构(二)——链表

    前言 人生总是直向前行走,从不留下什么. 原文地址:学习javascript数据结构(二)--链表 博主博客地址:Damonare的个人博客 正文 链表简介 上一篇博客-学习javascript数据结 ...

  6. linux内核数据结构之链表

    linux内核数据结构之链表 1.前言 最近写代码需用到链表结构,正好公共库有关于链表的.第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.后来看代码注释发现该 ...

  7. 数据结构之链表-链表实现及常用操作(C++篇)

    数据结构之链表-链表实现及常用操作(C++篇) 0.摘要 定义 插入节点(单向链表) 删除节点(单向链表) 反向遍历链表 找出中间节点 找出倒数第k个节点 翻转链表 判断两个链表是否相交,并返回相交点 ...

  8. python实现数据结构单链表

    #python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...

  9. JAVA数据结构之链表

    JAVA数据结构之链表 什么是链表呢? 链表作为最基本的数据结构之一,定义如下: 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的. 简单来说呢,链 ...

随机推荐

  1. 让Myeclipse自动生成的get set方法 自动加上文本注释,并且注释内容包含字段中我们加的文档注释

    在进行编码写实体类的时候发现,一个实体类有好多的字段要进行注释,他们都是私有的不能直接访问,我们在写的时候加入的文档注释也起不到效果,但是自动生成的get,set方法的文档注释有不符合我们要求(没有包 ...

  2. 听翁恺老师mooc笔记(15)--文件的输入与输出

    <>重定向 如果使用标准的printf输出,有一个比较简便的方法,可以将程序的结果写入一个文件.使用<和>符号,将程序运行结果重定向到文件中去,具体使用到的代码如下: ./te ...

  3. 听翁恺老师mooc笔记(6)--指针运算

    指针值加1就是将指针值加上sizeof(指针所指变量的类型) 1+1=2,那么指针加1是加上了1这个数字吗?试一下,在代码中定义了char数组,char也是整数,数组名是ac,ac中有10个元素,0- ...

  4. Alpha冲刺Day10

    Alpha冲刺Day10 一:站立式会议 今日安排: 由林静完成第三方机构的用户信息管理模块 由张梨贤完成第三方机构的委托授权管理模块 由黄腾飞和周静平完成政府人员模块下风险管控子模块下的核实企业风险 ...

  5. 201621123031 《Java程序设计》第1周学习总结

    作业01-Java基本概念 1.本周学习总结 1.本周学习内容:Java发展史(简述).Java语言特点.JDK .JRE .JVM .Java的开发步骤.Java开发工具. 2.关键概念之间的联系: ...

  6. Django 视图层

    URL映射 1.分布式url映射 include()函数提供分布式url映射功能,使URL映射可以被编写在多个url.py文件中 from django.conf.urls import url fr ...

  7. Python 远程部署 Fabric

    参考文章:http://zmrenwu.com/post/21/ Fabric是一个Python的库,它提供了丰富的同SSH交互的接口,可以用来在本地或远程机器上自动化.流水化地执行Shell命令.因 ...

  8. R语言基础2

    ----------------------------------R语言学习与科研应用,科研作图,数据统计挖掘分析,群:719954246-------------------------- 通常, ...

  9. SQL SERVER 游标的使用

    首先,关于什么是游标大家可以看看这篇文章,介绍得非常详细!! SQL Server基础之游标 下面是我自己的应用场景-- 有个需求,需要把数据库表里面某一个字段的值设为随机不重复的值. 表是这样的: ...

  10. 第三章Hibernate关联映射

    第三章Hibernate关联映射 一.关联关系 类与类之间最普通的关系就是关联关系,而且关联是有方向的. 以部门和员工为列,一个部门下有多个员工,而一个员工只能属于一个部门,从员工到部门就是多对一关联 ...