javascript实现数据结构与算法系列:功能完整的线性链表
由于链表在空间的合理利用上和插入,删除时不需要移动等的有点,因此在很多场合下,它是线性表的首选存储结构。然而,它也存在着实现某些基本操作,如求线性表长度时不如顺序存储结构的缺点;另一方面,由于在链表中,结点之间的关系使用指针来表示,则数据元素在线性表中的“位序”的概念已淡化,而被数据元素在线性链表中的“位置”所代替。为此,从实际出发重新定义线性链表及其基本操作
结构图:

(function(module){
function List() {
this.head = null;
this.tail = null;
}
module.exports = List;
List.mergeList = function (a, b, compare) {
var ha = a.head;
var hb = b.head;
var pa = ha;
var pb = hb;
var c = new List();
var q;
compare = compare || function (data1, data2) {
return data1 <= data2;
};
while (pa && pb) {
var data1 = pa.data;
var data2 = pb.data;
if (!compare(data1, data2)) {
// delete head node
q = a.delFirst();
// append the node to c linkedList
c.append(q);
pa = a.head;
} else {
q = b.delFirst();
c.append(q);
pb = b.head;
}
}
if (pa) {
c.append(pa);
} else {
c.append(pb);
}
return c;
};
List.prototype = {
makeNode: function(data, next){
return {
data: data != null ? data : null,
next: next || null
};
},
delFirst: function () {
var head = this.head;
this.head = this.head.next;
head.next = null;
if(this.head === null) this.tail = null;
return head;
},
append: function (node) {
if (this.head !== null) {
this.tail.next = node;
this.tail = this.tail.next;
} else {
this.head = node;
this.tail = node;
}
},
add: function (data) {
if (this.head === null) {
this.head = this.makeNode(data);
this.tail = this.head;
} else {
this.tail.next = this.makeNode(data);
this.tail = this.tail.next;
}
this.tail.data = data;
},
'delete': function (data) {
var current = this.head;
var previous = this.head;
var elem;
while (current !== null) {
if (data === current.data) {
if (current === this.head) {
this.head = current.next;
elem = current.data;
break;
}
if (current === this.tail) this.tail = previous;
previous.next = current.next;
elem = current.data;
break;
}
previous = current;
current = current.next;
}
if(this.head === null) this.tail = null;
return elem ? elem : false;
},
insertAsFirst: function (data) {
var temp = this.makeNode(data);
temp.next = this.head;
this.head = temp;
},
insertAfter: function (target, data) {
var current = this.head;
while (current !== null) {
if (current.data === target) {
var temp = this.makeNode(data);
temp.next = current.next;
if (current === this.tail) this.tail = temp;
current.next = temp;
return;
}
current = current.next;
}
},
item: function (index) {
var current = this.head;
while (current !== null) {
if (--index === 0) return current;
current = current.next;
}
return null;
},
each: function (callback) {
var current = this.head;
while (current !== null) {
callback(current);
current = current.next;
}
},
orderInsert: function(data, cmp){
cmp = typeof cmp === 'function' ? cmp : function (a, b){
if(a > b)
return 1;
else if(a === b)
return 0;
else
return -1;
};
var previous = this.head;
var current = this.head;
if(current === null){
this.head = this.tail = this.makeNode(data);
return;
}
var me = this;
while(current){
var ret = cmp(data, current.data);
// 如果插入元素大于当前元素,准备下次遍历
if(ret > 0){
previous = current;
current = current.next;
// 如果等于,直接插入到后面
} else if(ret === 0){
return insertBetween(data, previous, current);
// 如果小于则插入到前节点和当前节点中
// 因为已经是排序了,所以不需要多余判断了
} else {
if(this.head === previous && previous === current){
return this.insertAsFirst(data);
} else {
return insertBetween(data, previous, current);
}
}
}
// 插入到最后一个结点
previous.next = this.makeNode(data);
this.tail = previous.next;
function insertBetween(data, a, b){
var temp = me.makeNode(data);
temp.next = b;
a.next = temp;
return true;
}
}
};
/*
var list = new List();
list.add('b');
list.insertAsFirst('a');
list.insertAfter('b', 'c');
console.log(list.item(2));
console.log(JSON.stringify(list));
list.each(function (node) {
if (node.data === 'b') {
console.log('get b in each');
}
});
list['delete']('c');
list['delete']('a');
console.log(list);
var list2 = new List();
list2.add('c');
list2.insertAsFirst('d');
list2.insertAfter('d', 'b');
console.log(JSON.stringify(list2));
var list3 = List.mergeList(list, list2);
console.log(list3);
*/
/*
var list = new List();
list.orderInsert('e');
list.orderInsert('b');
list.orderInsert('c');
list.orderInsert('a');
list.orderInsert('d');
list.orderInsert('f');
*/
}(this.module || this));
以下是对应的单元测试代码:
describe('linkedList tests', function(){
var list = new List();
it('should find the second item', function(){
list.add('b');
expect(list.head.data).toBe('b');
expect(list.tail.next).toBe(null);
list.insertAsFirst('a');
expect(list.head.data).toBe('a');
expect(list.head.next.data).toBe('b');
list.insertAfter('b', 'c');
expect(list.item(2).data).toBe('b');
expect(list.tail.data).toBe('c');
});
it('should remove one item', function(){
expect(list['delete']('c')).toBe(true);
list['delete']('a');
expect(list.head.data).toBe('b');
});
var list2 = new List();
it('should match the json', function(){
list2.add('c');
list2.insertAsFirst('d');
list2.insertAfter('d', 'b');
expect(JSON.stringify(list2)).toBe('{"head":{"data":"d","next":{"data":"b","next":{"data":"c","next":null}}},"tail":{"data":"c","next":null}}');
});
it('should merge the lists', function(){
var list3 = List.mergeList(list, list2);
expect(list3.head.data).toBe('d');
expect(list3.head.next.data).toBe('b');
expect(list3.head.next.next.data).toBe('c');
expect(list3.tail.data).toBe('b');
});
});
javascript实现数据结构与算法系列:功能完整的线性链表的更多相关文章
- javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
- javascript实现数据结构与算法系列
1.线性表(Linear list) 线性表--简单示例及线性表的顺序表示和实现 线性表--线性链表(链式存储结构) 线性表的静态单链表存储结构 循环链表与双向链表 功能完整的线性链表 线性链表的例子 ...
- javascript实现数据结构与算法系列:循环链表与双向链表
循环链表(circular linked list) 是另一种形式的链式存储结构.它的特点是表中最后一个结点的指针域指向头结点,整个表形成一个环. 循环链表的操作和线性链表基本一致,仅有细微差别. w ...
- javascript实现数据结构与算法系列:线性表的静态单链表存储结构
有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...
- javascript实现数据结构与算法系列:队列 -- 链队列和循环队列实现及示例
1 队列的基本概念 队列(Queue):也是运算受限的线性表.是一种先进先出(First In First Out ,简称FIFO)的线性表.只允许在表的一端进行插入,而在另一端进行删除. 队首(fr ...
- C#数据结构与算法系列(四):链表——单链表(Single-LinkedList)
1.介绍: 链表是有序的列表,但是它在内存的存储如下: 链表是以节点的方式来存储,链式存储 每一个节点包含data域,next域:指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表 ...
- C#数据结构与算法系列(六):链表——双链表(Double-LinkedList)
1.对比单向链表 单向链表查找的方向只能是一个方向,而双向链表可以向前或者向后查找 单向链表不能自我删除,需要靠辅助节点,而双向链表可以自我删除 对于单向链表的删除,我们首先要找到单向链表待删除节点的 ...
- JavaScript 版数据结构与算法(二)队列
今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...
- 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解
数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
随机推荐
- 解决dropdownlist postback 在 iphone UIwebview 失效的问题
原因: IPhone UIWebView 的 用户代理 User Agent 在ASP.NET 4.0环境下是不识别的:所以ASP.NET提供了一个默认的,低级的不包括javascript的页面版本 ...
- RMAN 报:ORA-19504 ORA-27038
在itpub中看到下面的问题: oracle 10g备份脚本如下run{allocate channel d1 device type disk MAXPIECESIZE=100M;crosschec ...
- nginx 配置 ThinkPHP Rewrite
server { listen 80; server_name www.funsion.com; root /www/web/funsion; index index.php; location / ...
- MYSQL主键存在则更新,不存在则插入的解决方案(ON DUPLICATE KEY UPDATE)
经常我们使用的最简单的数据库操作就是数据的更新,删除和插入,对于批量删除和插入的方法相信大家都很清楚,那么批量更新估计有的人就不知道了,并且还有批量插入,在插入时若有主键冲突则更新的操作,这在EAV模 ...
- JavaScript 将多个引用(样式或者脚本)放入一个文件进行引用
1.将样式放入一个文件进行引用 @import url("../media/css/bootstrap.min.css"); @import url("../media/ ...
- SharePoint 2010 RBS 安装和配置遇到的一个问题
在按照微软官方的文档按照配置的时候遇到下面问题: <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event ...
- qt QSS文件伪状态
表 1. 伪状态列表伪状态 描述:checked button部件被选中:disabled 部件被禁用:enabled 部件被启用:focus 部件获得焦点:hover ...
- Json.Net使用JSON Schema验证JSON格式【实例】
给出一个Json,验证其格式是否符合规则. { "coord": { //对象 "lon": 145.77, "lat": -16.92 } ...
- 使用C语言在Win控制台中输出带颜色的文字
学了这么久的C语言,一直停留在编写“控制台”程序的水平.黑色窗口,白色的文字,看多了着实让人感到枯燥无味.但是作为业余爱好者,我既没有那么多时间和精力去学习如何编写窗口程序,也没有那个必要一定用C去调 ...
- Android 上传图片到 Asp.Net 服务器的问题
最近在做一个手机app联合系统管理做的应用程序,管理程序管理数据的发布和增删改查,手机app负责显示和操作业务逻辑这么一个功能. 刚开始路走的都很顺,但是走到通过Android客户端上传图片到Asp. ...