javascript实现数据结构:线性表--线性链表(链式存储结构)
上一节中, 线性表的顺序存储结构的特点是逻辑关系上相邻的两个元素在物理位置上也相邻,因此可以随机存取表中任一元素,它的存储位置可用一个简单,直观的公式来表示。然后,另一方面来看,这个特点也造成这种存储结构的弱点,在做插入或删除操作时,需移动大量元素。
而链式存储结构,由于它不需要逻辑上相邻的元素在物理位置上也相邻,因此它没有顺序存储结构所具有的弱点,但同时也失去了顺序表可随机存取的优点。
线性链表
wiki中的定义:
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
在计算机科学中,链表作为一种基础的数据结构可以用来生成其它类型的数据结构。链表通常由一连串节点组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向明上一个/或下一个节点的位置的链接("links")。链表最明显的好处就是,常规数组排列关联项目的方式可能不同于这些数据项目在记忆体或磁盘上顺序,数据的访问往往要在不同的排列顺序中转换。而链表是一种自我指示数据类型,因为它包含指向另一个相同类型的数据的指针(链接)。链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。链表有很多种不同的类型:单向链表,双向链表以及循环链表。
链表可以在多种编程语言中实现。像Lisp和Scheme这样的语言的内建数据类型中就包含了链表的访问和操作。程序语言或面向对象语言,如C/C++和Java依靠易变工具来生成链表。
线性表的链式存储结构的特点是用一组任意的存储单元储存线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。因此,为了表示每个数据元素a(i)与其直接后继数据元素a(i+1)之间的逻辑关系,对数据元素a(i)来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。这两部分信息组成数据元素a(i)的存储映像,称为结点(node)。它包括两个域:其中存储数据元素信息的域称为数据域;存储直接后继存储位置的域称为指针域,指针域中存储的信息称做指针或链。
又由于此链表的每个结点中只包含一个指针域,故又称线性链表或单链表。
单链表的整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。
同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空null。
链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。
![]()
一个单向链表包含两个值: 当前节点的值和一个指向下一个节点的链接
一个单向链表的节点被分成两个部分。第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址。单向链表只可向一个方向遍历。
// 线性表的单链表存储结构
function LNode(data, node) {
this.data = data;
this.next = node || null;
}
假设p是指向线性表中第i个数据元素(结点a(i))的指针,则p->next是指向第i+1个数据元素(结点a(i+1))的指针。
下面我们来看GetElem在单链表中的实现:
function getElem(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.data;
}
单链表的基本操作:
假设我们在线性表的两个数据元素a和b之间插入一个数据元素x,已知p为其单链表存储结构中指向结点a的指针。
插入:
假设s为指向结点x的指针,则可用语句描述:s->next = p->next; p->next = s;
删除:
假设p为指向结点a的指针,则修改指针的语句为: p->next = p->next->next;
实现:
function listInsert(i, data) {
var j = 0;
var p = this;
// 寻找第i-1个节点
while (p && j < i - 1) {
p = p.next;
++j;
}
// i < 1或者大于表长+1
if (!p || j > i - 1) return false;
// 生成新节点,插入p节点后面
p.next = new LNode(data, p.next);
return true;
}
function listDelete(i) {
var j = 0;
var p = this;
while (p.next && j < i - 1) {
p = p.next;
++j;
}
if (!p.next || j > i - 1) return false;
var q = p.next;
p.next = q.next;
return q.data;
}
单链表的其他操作
逆位序输入n个元素的值,建立带表头结点的单链线性表L。
function createList_L(n) {
var deferred = require('rsvp').defer();
var l = new LNode();
var count = n;
process.stdin.setEncoding('utf8');
process.stdin.on('data', function handler(data) {
console.log(123);
data = data.replace('\n', '');
l.next = new LNode(data, l.next);
if (!(--count)) {
console.log('pausing');
process.stdin.pause();
deferred.resolve(l);
}
});
return deferred.promise;
}
假设头指针为La和Lb的单链表分别为线性表LA和LB的存储结构,先要归并La和Lb得到单链表Lc:
function mergeList(a, b) {
var pa = a.next;
var pb = b.next;
// 用a的头结点作为c的头结点
var c = a;
var pc = a;
while (pa && pb) {
if (pa.data <= pb.data) {
pc.next = pa;
pc = pa;
pa = pa.next;
} else {
pc.next = pb;
pc = pb;
pb = pb.next;
}
}
// 插入剩余段
pc.next = pa ? pa : pb;
return c;
}
结构图:

完整代码:
// 单链表
/*
线性链表存储结构
整个链表的存取必须从头指针开始进行,头指针指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置。
同时,由于最后一个数据元素没有直接后继,则线性链表中最后一个结点的指针为空null。
*/ function LNode(data, node) {
this.data = data;
this.next = node || null;
}
LNode.prototype = {
// 时间复杂度O(n)
getElem: function getElem(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.data;
},
// 时间复杂度O(n)
listInsert: function listInsert(i, data) {
var j = 0;
var p = this;
// 寻找第i-1个节点
while (p && j < i - 1) {
p = p.next;
++j;
}
// i < 1或者大于表长+1
if (!p || j > i - 1) return false;
// 生成新节点,插入p节点后面
p.next = new LNode(data, p.next);
return true;
},
listDelete: function listDelete(i) {
var j = 0;
var p = this; while (p.next && j < i - 1) {
p = p.next;
++j;
} if (!p.next || j > i - 1) return false;
var q = p.next;
p.next = q.next;
return q.data;
}
}; LNode.createList_L = function createList_L(n) {
var deferred = require('D:\\node\\node_modules\\rsvp').defer();
var l = new LNode();
var count = n;
process.stdin.setEncoding('utf8'); process.stdin.on('data', function handler(data) {
console.log(123);
data = data.replace('\n', '');
l.next = new LNode(data, l.next);
if (!(--count)) {
console.log('pausing');
process.stdin.pause();
deferred.resolve(l);
}
}); return deferred.promise;
}; function deepCopy(obj) {
var newObj = {}; for (var i in obj) {
if (typeof obj[i] === 'object') {
newObj[i] = deepCopy(obj[i]);
} else {
newObj[i] = obj[i];
}
} return newObj;
} // TODO
/*
已知单链线性表a和b的元素按值非递减排列。
归并a和b得到新的单链线性表c,c的元素也按值非递减排列。
*/
LNode.mergeList = function mergeList(a, b) {
var pa = a.next;
var pb = b.next;
// 用a的头结点作为c的头结点
var c = a;
var pc = a; while (pa && pb) {
if (pa.data <= pb.data) {
pc.next = pa;
pc = pa;
pa = pa.next;
} else {
pc.next = pb;
pc = pb;
pb = pb.next;
}
} // 插入剩余段
pc.next = pa ? pa : pb; return c;
}; function log(list) {
var arr = []; do {
arr.push(list.data);
list = list.next;
} while (list); console.log(arr.join(','));
} void function test() {
var a1 = new LNode(1);
a1.listInsert(1, 2);
a1.listInsert(2, 3);
a1.listInsert(1, 4);
console.log(a1.getElem(1));
console.log(a1);
log(a1);
a1.listDelete(1);
console.log('a1 linkList:');
console.log(a1);
log(a1);
/*
LNode.createList_L(5)
.then(function(list){
console.log(list);
});
*/
var a2 = new LNode(3);
a2.listInsert(1, 3);
a2.listInsert(2, 8);
a2.listInsert(1, 4);
a2.listDelete(2);
console.log('a2 linkList');
log(a2); var a3 = LNode.mergeList(a2, a1);
console.log('merging linkLists');
console.log(a3);
log(a3);
}();
javascript实现数据结构:线性表--线性链表(链式存储结构)的更多相关文章
- c数据结构 -- 线性表之 顺序存储结构 于 链式存储结构 (单链表)
线性表 定义:线性表是具有相同特性的数据元素的一个有限序列 类型: 1:顺序存储结构 定义:把逻辑上相邻的数据元素存储在物理上相邻的存储单元中的存储结构 算法: #include <stdio. ...
- [置顶] ※数据结构※→☆线性表结构(queue)☆============优先队列 链式存储结构(queue priority list)(十二)
优先队列(priority queue) 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有 ...
- c数据结构 -- 线性表之 复杂的链式存储结构
复杂的链式存储结构 循环链表 定义:是一种头尾相接的链表(即表中最后一个结点的指针域指向头结点,整个链表形成一个环) 优点:从表中任一节点出发均可找到表中其他结点 注意:涉及遍历操作时,终止条件是判断 ...
- C++编程练习(2)----“实现简单的线性表的链式存储结构“
单链表采用链式存储结构,用一组任意的存储单元存放线性表的元素. 对于查找操作,单链表的时间复杂度为O(n). 对于插入和删除操作,单链表在确定位置后,插入和删除时间仅为O(1). 单链表不需要分配存储 ...
- C++线性表的链式存储结构
C++实现线性表的链式存储结构: 为了解决顺序存储不足:用线性表另外一种结构-链式存储.在顺序存储结构(数组描述)中,元素的地址是由数学公式决定的,而在链式储存结构中,元素的地址是随机分布的,每个元素 ...
- C语言实现链表(链式存储结构)
链表(链式存储结构)及创建 链表,别名链式存储结构或单链表,用于存储逻辑关系为 "一对一" 的数据.与顺序表不同,链表不限制数据的物理存储状态,换句话说,使用链表存储的数据元素,其 ...
- C++编程练习(6)----“实现简单的队列的链式存储结构“
队列的链式存储结构,其实就是线性表的单链表,只不过它只能尾进头出.简称链队列. 实现代码如下: /* LinkQueue.h 头文件 */ #include<iostream> #defi ...
- java资料——顺序存储结构和链式存储结构(转)
顺序存储结构 主要优点 节省存储空间,随机存取表中元素 缺 点 插入和删除操作需要移动元素 在计算机中用一组地址连续的存储单元依次存储线性表的各个数据元素,称作线性表的顺序存储结构. 顺序存储结 ...
- C++编程练习(4)----“实现简单的栈的链式存储结构“
如果栈的使用过程中元素数目变化不可预测,有时很小,有时很大,则最好使用链栈:反之,如果它的变化在可控范围内,使用顺序栈会好一些. 简单的栈的链式存储结构代码如下: /*LinkStack.h*/ #i ...
随机推荐
- 如何排查java.lang.NoSuchMethodError错误
今天碰到一个java.lang.NoSuchMethodException的异常.基本解决思路是: 1.检查类所在jar包的版本是否正确. 2.检查是否有jar包冲突,比如加载了多个版本的xxx.ja ...
- 十天学会单片机Day2键盘检测(独立键盘、矩阵键盘)
1.键盘的分类 编码键盘:键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或键值的称为编码键盘,如计算机键盘 非编码键盘:靠软件编程来识别的称为非编码键盘.独立键盘.矩阵键盘 2.按键消抖 ...
- python自学笔记一
之前看过一段时间的小甲鱼零基础自学python,b站上有高清免费资源[av4050443],但是作为零基础实在学得艰难,下载了python核心编程pdf,在这里做一些笔记. 虽然使用的是第二版的教材, ...
- python爬取网站数据
开学前接了一个任务,内容是从网上爬取特定属性的数据.正好之前学了python,练练手. 编码问题 因为涉及到中文,所以必然地涉及到了编码的问题,这一次借这个机会算是彻底搞清楚了. 问题要从文字的编码讲 ...
- mamp pro
MAMP PRO Settings and Files /Library/Application Support/appsolute/MAMP PRO ~/Library/Application Su ...
- NOJ1008-第几天
第几天 时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte总提交 : 2701 测试通过 : 800 ...
- 生产库MySQL配置文件my.cnf详解
OS:CentOS6.3 DB:5.6.16 [client] #客户端port = 3306 #数据库端口3306socket = /my/log/mysql.sock #MySQL套接字,多实例下 ...
- oracle 几个时间函数探究
近来经常用到时间函数,在此写一个笔记,记录自己的所得,希望也对您有所帮助. 1.对于一个时间如 sysdate:2015/1/30 14:16:03如何只得到年月日,同时它的数据类型不变化呢? 最容易 ...
- MongoDB牛刀小试
MongoDB基本操作 1.MongoDB的启动 首先创建一个目录作为MongoDB的工作目录: 进入MongoDB的bin目录: 执行mongod命令,使用参数--dbpath指定MongoDB的工 ...
- 通过FileWatcher,监听通过web上传的图片,并进行压缩
需求是这样的,通过web传输过来的图片,无论是JS上传,还是其他的上传方式,都需要生成2张缩略图,分别是用于商品列表的小图small,和用于分享的小图share.基于不同上传方式的不同需求,使用exe ...