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源码详解 对数组有不了解的可以先看看我的另一篇文章,那篇文章对数组有很多详细的解析,而本篇文章则着重讲动态数组,另一篇文章链接 ...
随机推荐
- .Net并行编程
1.什么是线程?线程和进程的区别是什么? 线程是程序执行的最小单元. 区别: 进程是操作系统进行资源处理和分配的最小单位,而一个进程可以包含多个线程,并共享进程的资源. 2.什么是多线程?为什么设计多 ...
- 共享内存shared pool (6):追踪sql语句
构建实验数据 --使用NC50用户查询(会话1) SQL> conn NC50/NC50 Connected. SQL> create table emp as select * from ...
- ldd3-2 构造和运行模块:环境搭建2
之前搭建了Ubuntu10.04驱动开发环境,但是那儿的内核版本是2.6.32.27,总感觉无从下手的感觉,因为书上的内核版本是2.6.10,作为初学者不知道差异在哪里,或许不应该纠结这个问题吧. 昨 ...
- USB协议分析
一.USB设备描述结构 1.逻辑组织结构 在USB设备的逻辑组织中,包含设备.配置.接口和端点4个层次.设备通常有一个或多个配置,配置通常有一个或多个接口,接口有零或多个端点. 每个USB设备都可以包 ...
- 第一节:CLR寄宿
本系列文章来自 CLR VIA C# .NET FrameWork在Microsoft Windows平台的顶部运行.这意味着.NET必须用Windows可以理解的技术来构建.首先,所有的托管模块和 ...
- 多线程报表生成其中报表以pdf形式保存
设计思路采用生产者消费者模式,生产者生产报表消费者消费报表生成pdf文件其中报表以html形式存储在线程安全列表中.使用到技术有:多线程协作,线程池,线程安全,html 生成pdf. 一.生产者生成h ...
- oracle 几个时间函数探究
近来经常用到时间函数,在此写一个笔记,记录自己的所得,希望也对您有所帮助. 1.对于一个时间如 sysdate:2015/1/30 14:16:03如何只得到年月日,同时它的数据类型不变化呢? 最容易 ...
- Extjs-工具条和菜单 Ext.menu和Ext.Toolbar
转载自:http://blog.csdn.net/itlwc/article/details/7878002 1.创建一个简单工具条效果图 <script type="text/jav ...
- Learning note for Binding and validation
Summary of my learning note for WPF Binding Binding to DataSet. when we want to add new record, we s ...
- mini6410-JNI-led
一.编写JNI模块 当安装好NDK编译环境后,会在它的目录下找到sample目录,它里面有一些例子,可以参考这些例子来写我们自已的模块. 1.在/home/android/文件夹下,新建“ledjni ...