循环链表(circular linked list)

是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个表形成一个环。

循环链表的操作和线性链表基本一致,仅有细微差别。

wiki

在一个 循环链表中, 首节点和末节点被连接在一起。这种方式在单向和双向链表中皆可实现。要转换一个循环链表,你开始于任意一个节点然后沿着列表的任一方向直到返回开始的节点。再来看另一种方法,循环链表可以被视为“无头无尾”。这种列表很利于节约数据存储缓存, 假定你在一个列表中有一个对象并且希望所有其他对象迭代在一个非特殊的排列下。

指向整个列表的指针可以被称作访问指针。


用单向链表构建的循环链表

循环链表中第一个节点之前就是最后一个节点,反之亦然。循环链表的无边界使得在这样的链表上设计算法会比普通链表更加容易。对于新加入的节点应该是在第一个节点之前还是最后一个节点之后可以根据实际要求灵活处理,区别不大(详见下面实例代码)。当然,如果只会在最后插入数据(或者只会在之前),处理也是很容易的。

另外有一种模拟的循环链表,就是在访问到最后一个节点之后的时候,手工的跳转到第一个节点。访问到第一个节点之前的时候也一样。这样也可以实现循环链表的功能,在直接用循环链表比较麻烦或者可能会出现问题的时候可以用。

双向链表(double linked list)

双向链表是为了克服单链表这种单向性的缺点。

双向链表的结点中有两个指针域,其一指向直接后继,另一指向直接前趋。

双向链表也可以有循环表。

wiki

一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个连接:一个指向前一个节点,(当此“连接”为第一个“连接”时,指向空值或者空列表);而另一个指向下一个节点,(当此“连接”为最后一个“连接”时,指向空值或者空列表)


一个双向链表有三个整数值: 数值, 向后的节点链接, 向前的节点链接

在一些低级语言中, XOR-linking 提供一种在双向链表中通过用一个词来表示两个链接(前后),我们通常不提倡这种做法。

双向链表也叫双链表双向链表中不仅有指向后一个节点的指针,还有指向前一个节点的指针。这样可以从任何一个节点访问前一个节点,当然也可以访问后一个节点,以至整个链表。一般是在需要大批量的另外储存数据在链表中的位置的时候用。双向链表也可以配合下面的其他链表的扩展使用。

由于另外储存了指向链表内容的指针,并且可能会修改相邻的节点,有的时候第一个节点可能会被删除或者在之前添加一个新的节点。这时候就要修改指向首个节点的指针。有一种方便的可以消除这种特殊情况的方法是在最后一个节点之后、第一个节点之前储存一个永远不会被删除或者移动的虚拟节点,形成一个下面说的循环链表。这个虚拟节点之后的节点就是真正的第一个节点。这种情况通常可以用这个虚拟节点直接表示这个链表,对于把链表单独的存在数组里的情况,也可以直接用这个数组表示链表并用第0个或者第-1个(如果编译器支持)节点固定的表示这个虚拟节点。

结构图:

实现:

 (function(module){
function DuLNode(data, prior, next) {
this.data = data;
this.prior = prior || this;
this.next = next || this;
}
module.exports = DuLNode;
DuLNode.prototype = {
getElem: function (i) {
// 初始化,p指向第一个节点,j为计数器
var p = this.next;
var j = 1;
// 顺指针向后查找,知道p指向第i个元素或p为空
while (p && j < i) {
p = p.next;
++j;
}
// 第i个元素不存在
// 或者取第i个元素
return (!p || j > i) ? null : p;
},
listInsert: function (i, elem) {
var p; if (!(p = this.getElem(i))) return false; var s = new DuLNode(elem, p.prior, p);
p.prior.next = s;
p.prior = s; return true;
},
listDelete: function (i) {
var p;
if (!(p = this.getElem(i))) return false; var e = p.data;
p.prior.next = p.next;
p.next.prior = p.prior; p = null; return e;
}
};
/*
var a = new DuLNode(1); a.listInsert(0, 1);
a.listInsert(1, 2);
a.listInsert(2, 3);
a.listDelete(1);
console.log(a);
*/
})(this.module || this);

最新文章

  1. plain framework 1 一款主要用于网络(游戏)开发的C/C++开源框架 安装篇 updated
  2. Ideas about the future of management
  3. [ucgui] 彩色条函数
  4. electronic data interchange 电子数据交换
  5. Core Java Volume I — 3.10. Arrays
  6. 炼数成金hadoop视频干货02
  7. C#中子类调用父类的实现方法
  8. Elasticsearch从0.90(0.90.x)到1.2(1.x)API的变化-二
  9. Appium 提高脚本复用、可配置性
  10. [BZOJ 2440] [中山市选2011] 完全平方数 【二分 + 莫比乌斯函数】
  11. [R] /usr/share/doc/apache2/README.Debian.gz
  12. HttpClient发送get post请求和数据解析
  13. Asp.net+jquery+ajaxpro异步仿Facebook纵向时间轴效果
  14. VC6.0 突然打不开dsw 工程文件的解决方案
  15. lvy打包到本地
  16. 关于在linux下安装git,以及在idea上将项目部署到码云上
  17. 深入Redis持久化
  18. AngularJS获取项目中定义的json文件
  19. webpack+sass+vue 入门教程(二)
  20. 小白学习安全测试(三)——扫描工具-Nikto使用

热门文章

  1. SQL Server 基础之《学生表-教师表-课程表-选课表》
  2. 使用WIF实现单点登录Part IV —— 常见问题
  3. 14.python中的集合
  4. zip解压缩
  5. 通过java反射实现简单的关于MongoDB的对象关系映射(ORM).
  6. Java并发编程实战---第六章:任务执行
  7. hdu 4593 Robot
  8. JVM规范小结
  9. 鲁棒性是 Robustness
  10. Web开发者和设计师必须要知道的 iOS 8 十个变化