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

结构图:

 (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实现数据结构与算法系列:功能完整的线性链表的更多相关文章

  1. javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例

    栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...

  2. javascript实现数据结构与算法系列

    1.线性表(Linear list) 线性表--简单示例及线性表的顺序表示和实现 线性表--线性链表(链式存储结构) 线性表的静态单链表存储结构 循环链表与双向链表 功能完整的线性链表 线性链表的例子 ...

  3. javascript实现数据结构与算法系列:循环链表与双向链表

    循环链表(circular linked list) 是另一种形式的链式存储结构.它的特点是表中最后一个结点的指针域指向头结点,整个表形成一个环. 循环链表的操作和线性链表基本一致,仅有细微差别. w ...

  4. javascript实现数据结构与算法系列:线性表的静态单链表存储结构

    有时可借用一维数组来描述线性链表,这就是线性表的静态单链表存储结构. 在静态链表中,数组的一个分量表示一个结点,同时用游标(cur)代替指针指示结点在数组中的相对位置.数组的第0分量可看成头结点,其指 ...

  5. javascript实现数据结构与算法系列:队列 -- 链队列和循环队列实现及示例

    1 队列的基本概念 队列(Queue):也是运算受限的线性表.是一种先进先出(First In First Out ,简称FIFO)的线性表.只允许在表的一端进行插入,而在另一端进行删除. 队首(fr ...

  6. C#数据结构与算法系列(四):链表——单链表(Single-LinkedList)

    1.介绍: 链表是有序的列表,但是它在内存的存储如下:  链表是以节点的方式来存储,链式存储 每一个节点包含data域,next域:指向下一个节点 链表的各个节点不一定是连续存储 链表分带头节点的链表 ...

  7. C#数据结构与算法系列(六):链表——双链表(Double-LinkedList)

    1.对比单向链表 单向链表查找的方向只能是一个方向,而双向链表可以向前或者向后查找 单向链表不能自我删除,需要靠辅助节点,而双向链表可以自我删除 对于单向链表的删除,我们首先要找到单向链表待删除节点的 ...

  8. JavaScript 版数据结构与算法(二)队列

    今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...

  9. 数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解

    数据结构与算法系列2 线性表 使用java实现动态数组+ArrayList源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...

随机推荐

  1. Python学习教程(learning Python)--2.2.2 Python全局和局部变量

    Python的变量也有全局和局部变量之分. 1. 局部变量 用在子函数里的变量称之为局部变量,其生命周期为该函数执行周期,即函数执行完后变量即不存在.由于局部变量和某个函数直接相关,故不同子函数里可以 ...

  2. Redhat 6环境下安装Oracle 12c的方法

    Step 1: 要在Linux上安装Oracle,需要在安装Oracle之前安装好相应的软件包,在不同操作系统环境下,对软件包的要求各不相同.具体对应的软件包,见官网文档:https://docs.o ...

  3. (1)c语言学习总结之从关键字到循环结构

    一.关键字和标示符 1.关键字:c规定的有特殊含义的单词(也就是系统起的名字),全部是小写,有32个; 由关键字引出数据类型和流程类型 1.分类: (1)数据类型:整型用int标示,字符型用char表 ...

  4. VBA在WORD中给表格外的字体设置为标题

    使用VB可以将表外的字体设置标题字体实际操作如下: VB代码如下: Sub oliver_1() Selection.EndKey Unit:=wdStory '光标移到文末 To ActiveDoc ...

  5. Java并发编程实战---第六章:任务执行

    废话开篇 今天开始学习Java并发编程实战,很多大牛都推荐,所以为了能在并发编程的道路上留下点书本上的知识,所以也就有了这篇博文.今天主要学习的是任务执行章节,主要讲了任务执行定义.Executor. ...

  6. hdu 2544 最短路

    题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=2544 最短路 Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shi ...

  7. HTTP网页错误代码大全带解释

    HTTP网页错误代码大全带解释 HTTP 400 - 请求无效HTTP 401.1 - 未授权:登录失败HTTP 401.2 - 未授权:服务器配置问题导致登录失败HTTP 401.3 - ACL 禁 ...

  8. MongoDB 数据类型

    MongoDB支持许多数据类型的列表下面给出: String : 这是最常用的数据类型来存储数据.在MongoDB中的字符串必须是有效的UTF-8. Integer : 这种类型是用来存储一个数值.整 ...

  9. 扒一扒编辑距离(Levenshtein Distance)算法

    最近由于工作需要,接触了编辑距离(Levenshtein Distance)算法.赶脚很有意思.最初百度了一些文章,但讲的都不是很好,读起来感觉似懂非懂.最后还是用google找到了一些资料才慢慢理解 ...

  10. [转]ubuntu server上网配置

    [转]ubuntu server上网配置 http://blog.sina.com.cn/s/blog_6c9d65a101011pyt.html 今天我的ubuntu server上不去网了,所以重 ...