javascript实现数据结构: 串的块链存储表示
和线性表的链式存储结构相类似,也可采用链式方式存储串值。由于串结构的特殊性--结构中的每个数据元素是一个字符,则用链表存储串值时,存在一个“结点大小”的问题,即每个结点可以存放一个字符,也可以存放多个字符。
下面是结点大小为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实现数据结构: 串的块链存储表示的更多相关文章
- javascript实现数据结构:串--定长顺序存储表示以及kmp算法实现
		
串(string)(或字符串)是由零个或多个字符组成的有限序列.串中字符的数目称为串的长度.零个字符的串称为空串(null string),它的长度为零. 串中任意个连续的字符组成的子序列称为该串的子 ...
 - 数据结构——串(KMP)
		
空串:长度为0的串 空格串:由一个或多个空格组成的串 串常用的3种机内表示方法: 定长顺序存储表示: 用一组地址连续的存储单元存储串的字符序列,每一个串变量都有一个固定长度的存储区,可用定长数组来描述 ...
 - javascript实现数据结构与算法系列
		
1.线性表(Linear list) 线性表--简单示例及线性表的顺序表示和实现 线性表--线性链表(链式存储结构) 线性表的静态单链表存储结构 循环链表与双向链表 功能完整的线性链表 线性链表的例子 ...
 - javascript实现数据结构与算法系列:栈 -- 顺序存储表示和链式表示及示例
		
栈(Stack)是限定仅在表尾进行插入或删除操作的线性表.表尾为栈顶(top),表头为栈底(bottom),不含元素的空表为空栈. 栈又称为后进先出(last in first out)的线性表. 堆 ...
 - javascript实现数据结构:广义表
		
原文:javascript实现数据结构:广义表 广义表是线性表的推广.广泛用于人工智能的表处理语言Lisp,把广义表作为基本的数据结构. 广义表一般记作: LS = (a1, a2, ..., an ...
 - JavaScript 版数据结构与算法(二)队列
		
今天,我们要讲的是数据结构与算法中的队列. 队列简介 队列是什么?队列是一种先进先出(FIFO)的数据结构.队列有什么用呢?队列通常用来描述算法或生活中的一些先进先出的场景,比如: 在图的广度优先遍历 ...
 - javascript中的作用域与作用域链
		
前几天,在写一段js代码时,出现了一些问题,调了很长时间也没有调通,其原因是,我在处理变量的作用域时错误地沿用了C++的作用域机制.因此我回炉了一次. 如果你使用过C++或java等一系列的面向对象的 ...
 - 深入理解JavaScript中的作用域、作用域链和闭包
		
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qappleh/article/detai ...
 - PHP之区域块链
		
搭建一个最简单的区块链吧.代码简单易懂. <?php //区域块链 //block 区块 // chain 链 //data //之前区块的has值 //自己的has值 : 他是由存储在区块链 ...
 
随机推荐
- ubuntu16.04 chromium浏览器无法启动
			
点击浏览器不能启动,在终端输入: chromium -browser %U 错误如下: [/)] NSS_VersionCheck("3.26") failed. NSS > ...
 - gitlab忘记管理员密码
			
gitlab忘记密码后破解! gitlab-rails console production :> user = User.).first irb(main)::> user.passwo ...
 - get请求和post的请求的区别
			
https://www.cnblogs.com/logsharing/p/8448446.html
 - MVC4设置伪静态---路由伪静态
			
有些客户要求设置静态的,为了完成需求,而且更简单的做法就是设置伪静态,例如:http://localhost:80/Home/Index.html ,也可以访问http://localhost:80/ ...
 - HDU6464 (权值线段树)-(查找区间第k1小于第k2小之间的和)
			
http://acm.hdu.edu.cn/showproblem.php?pid=6464 不理解先看博客:https://blog.csdn.net/g21glf/article/details/ ...
 - HDU - 1024 M子段最大和 简单DP
			
如何确保每个段至少一个数是关键(尤其注意负数情况) #include<iostream> #include<algorithm> #include<cstdio> ...
 - Android 通过网络获取图片的源码
			
将开发过程中经常用到的内容做个备份,如下的资料是关于Android 通过网络获取图片的的内容. package com.netimg; import android.app.Activity;impo ...
 - ASP.Net Core 发布ABP项目遇到的错误
			
1.HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效. 与ASP.NET时代不同,ASP.NET Core不再是由IIS工作 ...
 - webAPI过滤器返回数据加密
			
项目需求: 接口返回的数据,存在一些敏感信息,不希望其他用户看到,将Data进行加密传输 代码如下: public class EncryptDataFilterAttribute : ActionF ...
 - 使用 .NET Core CLI 创建 .NET Core 全局工具
			
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=2&ch=&tn=baiduhome_pg& ...