和线性表的链式存储结构相类似,也可采用链式方式存储串值。由于串结构的特殊性--结构中的每个数据元素是一个字符,则用链表存储串值时,存在一个“结点大小”的问题,即每个结点可以存放一个字符,也可以存放多个字符。

下面是结点大小为4(即每个结点存放4个字符)的链表:

head --> (a) --> (b) --> (c) --> ... --> (i)

当结点大小大于1时,由于串长不一定是结点大小的整倍数,则链表中的最后一个结点不一定全被串值占满,此时通常补上“#”或其它非串值字符。

为了便于进行串的操作,当以链表存储串值时,除头指针外还可附设一个尾指针指示链表中的最后一个结点,并给出当前串的长度,称如此定义的串存储结构为块链结构。

由于一般情况下,对串进行操作时,只需要从头向尾顺序扫描即可,则对串值不必建立双向链表。设尾指针的目的是为了便于进行连接操作,但应注意连接时需处理第一个串尾的无效字符。

在链式存储方式中,结点大小的选择和顺序存储方式的格式选择一样都很重要,它直接影响到串处理的效率。如果串很长,这要求我们考虑串值的存储密度:

存储密度 = 串值所占的存储位 / 实际分配的存储位

串值的链式存储结构对某些串操作,如连接操作等有一定方便之处,但总的来说不如另外两种存储结构灵活,它占用存储量大且操作复杂。

结构图:

实现代码:

 function Chunk(chunkSize) {
this.chunkSize = chunkSize || 4;
this.ch = [];
for (var i = 0; i < this.chunkSize; i++) {
this.ch[i] = '#';
}
// type: Chunk
this.next = null;
} exports.LString = LString;
function LString(chunkSize) {
// type Chunk
this.head = null;
// type: chunk
this.tail = null;
// 串的当前长度
this.length = 0;
this.chunkSize = chunkSize || 4;
} LString.prototype = {
// 将字符串转换成LString类型
strAssign: function (chars) {
this.head = this.tail = new Chunk(this.chunkSize);
this.length = chars.length; var current = this.head;
for (var i = 0, len = chars.length; i < len; i++) {
current.ch[i % this.chunkSize] = chars[i];
if (i + 1 < len && (i + 1) % this.chunkSize === 0) {
current.next = new Chunk();
current = current.next;
}
} this.tail = current;
},
// 字符串对比
// TODO 是否去掉chunkSize的对比
strCompare: function (tLString) {
var current = this.head;
var curT = tLString.head; if (this.length !== tLString.length) return false; while (current) {
for (var i = 0; i < this.chunkSize; i++) {
if (current.ch[i] !== curT.ch[i]) return false;
} current = current.next;
curT = curT.next;
} return true;
},
clearString: function () {
this.head = this.tail = null;
this.length = 0;
},
concat: function (tLSting) {
if (!tLSting.length) return; var ret = new LString(this.chunkSize); if (this.head === null) {
copyString(ret, tLSting);
} else {
ret.head = ret.tail = new Chunk(this.chunkSize);
copyString(ret, this); var index = ret.tail.ch.indexOf('#');
if (index === -1) {
copyString(ret, tLSting);
} else {
copyString(ret, tLSting, ret.tail, tLSting.head, index);
}
} return ret;
},
substring: function (pos, len) {
pos = ~~pos || 0;
len = ~~len || this.length;
if (pos < 0 || pos > this.length - 1 || len < 0 || len > this.length - pos)
throw new Error('unexpected parameter'); var sub = new LString(this.chunkSize);
var current = findPosChunk(this, pos);
var curS = sub.head = new Chunk(this.chunkSize);
var i = 0;
sub.length = len; outerloop: while (current) {
for (var j = 0, size = this.chunkSize; j < size; j++) {
if (i === len) {
break outerloop;
} else {
curS.ch[j] = current.ch[(i + pos) % this.chunkSize];
i++;
if ((i + pos) % this.chunkSize === 0) {
current = current.next;
}
if (i % this.chunkSize === 0 && (current.ch[i] || current.next)) {
curS.next = new Chunk(this.chunkSize);
curS = curS.next;
}
}
}
} return sub;
},
toString: function () {
var current = this.head; if (current === null) return ''; var str = '';
while (current) {
for (var i = 0, len = this.chunkSize; i < len; i++) {
var ch = current.ch[i];
if (ch === '#') {
return str;
} else {
str += current.ch[i];
}
}
current = current.next;
} return str;
}
}; function findPosChunk(lString, pos) {
var current = lString.head;
while (current) {
for (var i = 0, len = lString.chunkSize; i < len; i++) {
if (pos-- === 0) return current;
}
current = current.next;
}
} function copyString(destination, target, curD, currT, offset) {
offset = offset || 0;
currT = currT || target.head;
curD = curD || destination.head;
var k = 0; while (currT) {
for (var i = 0, len = target.chunkSize; i < len; i++, k++) {
var j = k % curD.chunkSize + offset;
curD.ch[j % curD.chunkSize] = currT.ch[i]; if ((j + 1) % curD.chunkSize === 0 && (currT.ch[i + 1] || currT.next)) {
curD.next = new Chunk(destination.chunkSize);
curD = curD.next;
}
} currT = currT.next;
} destination.tail = curD;
destination.length += target.length;
} var a = new LString();
var b = new LString();
var c = new LString(); a.strAssign('abcdefg');
console.log(a + '');
b.strAssign('hijklmno');
console.log(b + '');
c.strAssign('abcdefg');
console.log(a.strCompare(b));
console.log(a.strCompare(c));
var t = a.concat(b);
console.log(t + '');
t = t.substring(2, 5);
console.log(t + '');

单元测试代码:

 describe('LString tests', function(){
var a = new LString(5);
var b = new LString(4);
var c = new LString(5);
var t; it('should assign string', function(){
a.strAssign('abcdefg');
expect(a + '').toBe('abcdefg'); b.strAssign('hijklmno');
expect(b + '').toBe('hijklmno'); c.strAssign('abcdefg');
expect(c + '').toBe('abcdefg');
}); it('should compare', function(){
expect(a.strCompare(b)).toBe(false);
expect(a.strCompare(c)).toBe(true);
}); it('should concat', function(){
t = a.concat(b);
expect(t + '').toBe('abcdefghijklmno');
}); it('should substring', function(){
t = t.substring(2, 5);
expect(t + '').toBe('cdefg');
});
});

javascript实现数据结构: 串的块链存储表示的更多相关文章

  1. javascript实现数据结构:串--定长顺序存储表示以及kmp算法实现

    串(string)(或字符串)是由零个或多个字符组成的有限序列.串中字符的数目称为串的长度.零个字符的串称为空串(null string),它的长度为零. 串中任意个连续的字符组成的子序列称为该串的子 ...

  2. 数据结构——串(KMP)

    空串:长度为0的串 空格串:由一个或多个空格组成的串 串常用的3种机内表示方法: 定长顺序存储表示: 用一组地址连续的存储单元存储串的字符序列,每一个串变量都有一个固定长度的存储区,可用定长数组来描述 ...

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

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

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

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

  5. javascript实现数据结构:广义表

    原文:javascript实现数据结构:广义表  广义表是线性表的推广.广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构. 广义表一般记作: LS = (a1, a2, ..., an ...

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

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

  7. javascript中的作用域与作用域链

    前几天,在写一段js代码时,出现了一些问题,调了很长时间也没有调通,其原因是,我在处理变量的作用域时错误地沿用了C++的作用域机制.因此我回炉了一次. 如果你使用过C++或java等一系列的面向对象的 ...

  8. 深入理解JavaScript中的作用域、作用域链和闭包

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qappleh/article/detai ...

  9. PHP之区域块链

    搭建一个最简单的区块链吧.代码简单易懂. <?php //区域块链 //block 区块 // chain 链 //data  //之前区块的has值 //自己的has值 : 他是由存储在区块链 ...

随机推荐

  1. layer.open中content里面的元素追加click事件,触发不了

    [注意] 事件要追加在触发弹出事件的点击事件里面 $('#feedback').click(function(){ layer.open({ content:'<div><div c ...

  2. vue 实现表单中password输入的显示与隐藏.

    实现效果: 点击 “眼睛” 的时候显示与隐藏 代码: <!DOCTYPE html> <html lang="en"> <head> <m ...

  3. 批量删除Maven中失败的下载项

    [摘自] http://stackoverflow.com/questions/5074063/maven-error-failure-to-transfer Remove all your fail ...

  4. Oracle "set define off" 关闭替代变量功能

    set define off关闭替代变量功能 在SQL*Plus中默认的"&"表示替代变量,也就是说,只要在命令中出现该符号,SQL*Plus就会要你输入替代值.这就意味着 ...

  5. ssh无密码登录和scp无密码拷贝

    目的:在A主机上无密码登录B主机 方法: A主机生成密钥:ssh-keygen -t rsa 将密钥复制到B主机:cat ~/.ssh/id_rsa.pub | ssh root@B 'cat > ...

  6. vue中遇到的坑 --- 变化检测问题(数组相关)

    最近在项目中遇到了一个问题,不知道为什么,所以最后通过动手做demo实践.查文档的方式解决了,这里做一个总结. 例1 <!DOCTYPE html> <html lang=" ...

  7. git命令(转载学习)

    Git使用教程 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是 ...

  8. pat1007. Maximum Subsequence Sum (25)

    1007. Maximum Subsequence Sum (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Y ...

  9. 4.爬虫 requests库讲解 GET请求 POST请求 响应

    requests库相比于urllib库更好用!!! 0.各种请求方式 import requests requests.post('http://httpbin.org/post') requests ...

  10. BNU4286——Adjacent Bit Counts——————【dp】

    Adjacent Bit Counts Time Limit: 1000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Jav ...