javascript實現數據結構: 串的塊鏈存儲表示

和線性表的鏈式存儲結構相相似,也可採用鏈式方式存儲串值。因爲串結構的特殊性--結構中的每一個數據元素是一個字符,則用鏈表存儲串值時,存在一個「結點大小」的問題,即每一個結點能夠存放一個字符,也能夠存放多個字符。ide

下面是結點大小爲4(即每一個結點存放4個字符)的鏈表:oop

head --> (a) --> (b) --> (c) --> ... --> (i)單元測試

當結點大小大於1時,因爲串長不必定是結點大小的整倍數,則鏈表中的最後一個結點不必定全被串值佔滿,此時一般補上「#」或其它非串值字符。測試

爲了便於進行串的操做,當以鏈表存儲串值時,除頭指針外還可附設一個尾指針指示鏈表中的最後一個結點,並給出當前串的長度,稱如此定義的串存儲結構爲塊鏈結構。this

因爲通常狀況下,對串進行操做時,只須要從頭向尾順序掃描便可,則對串值沒必要創建雙向鏈表。設尾指針的目的是爲了便於進行鏈接操做,但應注意鏈接時需處理第一個串尾的無效字符。spa

在鏈式存儲方式中,結點大小的選擇和順序存儲方式的格式選擇同樣都很重要,它直接影響到串處理的效率。若是串很長,這要求咱們考慮串值的存儲密度:prototype

存儲密度 = 串值所佔的存儲位 / 實際分配的存儲位指針

 

串值的鏈式存儲結構對某些串操做,如鏈接操做等有必定方便之處,但總的來講不如另外兩種存儲結構靈活,它佔用存儲量大且操做複雜。code

 

結構圖:blog

實現代碼:

  1 function Chunk(chunkSize) {
  2         this.chunkSize = chunkSize || 4;
  3         this.ch = [];
  4         for (var i = 0; i < this.chunkSize; i++) {
  5             this.ch[i] = '#';
  6         }
  7         // type: Chunk
  8         this.next = null;
  9     }
 10 
 11     exports.LString = LString;
 12     function LString(chunkSize) {
 13         // type Chunk
 14         this.head = null;
 15         // type: chunk
 16         this.tail = null;
 17         // 串的當前長度
 18         this.length = 0;
 19         this.chunkSize = chunkSize || 4;
 20     }
 21 
 22     LString.prototype = {
 23         // 將字符串轉換成LString類型
 24         strAssign: function (chars) {
 25             this.head = this.tail = new Chunk(this.chunkSize);
 26             this.length = chars.length;
 27 
 28             var current = this.head;
 29             for (var i = 0, len = chars.length; i < len; i++) {
 30                 current.ch[i % this.chunkSize] = chars[i];
 31                 if (i + 1 < len && (i + 1) % this.chunkSize === 0) {
 32                     current.next = new Chunk();
 33                     current = current.next;
 34                 }
 35             }
 36 
 37             this.tail = current;
 38         },
 39         // 字符串對比
 40         // TODO 是否去掉chunkSize的對比
 41         strCompare: function (tLString) {
 42             var current = this.head;
 43             var curT = tLString.head;
 44 
 45             if (this.length !== tLString.length) return false;
 46 
 47             while (current) {
 48                 for (var i = 0; i < this.chunkSize; i++) {
 49                     if (current.ch[i] !== curT.ch[i]) return false;
 50                 }
 51 
 52                 current = current.next;
 53                 curT = curT.next;
 54             }
 55 
 56             return true;
 57         },
 58         clearString: function () {
 59             this.head = this.tail = null;
 60             this.length = 0;
 61         },
 62         concat: function (tLSting) {
 63             if (!tLSting.length) return;
 64 
 65             var ret = new LString(this.chunkSize);
 66 
 67             if (this.head === null) {
 68                 copyString(ret, tLSting);
 69             } else {
 70                 ret.head = ret.tail = new Chunk(this.chunkSize);
 71                 copyString(ret, this);
 72 
 73                 var index = ret.tail.ch.indexOf('#');
 74                 if (index === -1) {
 75                     copyString(ret, tLSting);
 76                 } else {
 77                     copyString(ret, tLSting, ret.tail, tLSting.head, index);
 78                 }
 79             }
 80 
 81             return ret;
 82         },
 83         substring: function (pos, len) {
 84             pos = ~~pos || 0;
 85             len = ~~len || this.length;
 86             if (pos < 0 || pos > this.length - 1 || len < 0 || len > this.length - pos)
 87                 throw new Error('unexpected parameter');
 88 
 89             var sub = new LString(this.chunkSize);
 90             var current = findPosChunk(this, pos);
 91             var curS = sub.head = new Chunk(this.chunkSize);
 92             var i = 0;
 93             sub.length = len;
 94 
 95             outerloop: while (current) {
 96                 for (var j = 0, size = this.chunkSize; j < size; j++) {
 97                     if (i === len) {
 98                         break outerloop;
 99                     } else {
100                         curS.ch[j] = current.ch[(i + pos) % this.chunkSize];
101                         i++;
102                         if ((i + pos) % this.chunkSize === 0) {
103                             current = current.next;
104                         }
105                         if (i % this.chunkSize === 0 && (current.ch[i] || current.next)) {
106                             curS.next = new Chunk(this.chunkSize);
107                             curS = curS.next;
108                         }
109                     }
110                 }
111             }
112 
113             return sub;
114         },
115         toString: function () {
116             var current = this.head;
117 
118             if (current === null) return '';
119 
120             var str = '';
121             while (current) {
122                 for (var i = 0, len = this.chunkSize; i < len; i++) {
123                     var ch = current.ch[i];
124                     if (ch === '#') {
125                         return str;
126                     } else {
127                         str += current.ch[i];
128                     }
129                 }
130                 current = current.next;
131             }
132 
133             return str;
134         }
135     };
136 
137     function findPosChunk(lString, pos) {
138         var current = lString.head;
139         while (current) {
140             for (var i = 0, len = lString.chunkSize; i < len; i++) {
141                 if (pos-- === 0) return current;
142             }
143             current = current.next;
144         }
145     }
146 
147     function copyString(destination, target, curD, currT, offset) {
148         offset = offset || 0;
149         currT = currT || target.head;
150         curD = curD || destination.head;
151         var k = 0;
152 
153         while (currT) {
154             for (var i = 0, len = target.chunkSize; i < len; i++, k++) {
155                 var j = k % curD.chunkSize + offset;
156                 curD.ch[j % curD.chunkSize] = currT.ch[i];
157 
158                 if ((j + 1) % curD.chunkSize === 0 && (currT.ch[i + 1] || currT.next)) {
159                     curD.next = new Chunk(destination.chunkSize);
160                     curD = curD.next;
161                 }
162             }
163 
164             currT = currT.next;
165         }
166 
167         destination.tail = curD;
168         destination.length += target.length;
169     }
170 
171     var a = new LString();
172     var b = new LString();
173     var c = new LString();
174 
175     a.strAssign('abcdefg');
176     console.log(a + '');
177     b.strAssign('hijklmno');
178     console.log(b + '');
179     c.strAssign('abcdefg');
180     console.log(a.strCompare(b));
181     console.log(a.strCompare(c));
182     var t = a.concat(b);
183     console.log(t + '');
184     t = t.substring(2, 5);
185     console.log(t + '');

 

單元測試代碼:

 1 describe('LString tests', function(){
 2     var a = new LString(5);
 3     var b = new LString(4);
 4     var c = new LString(5);
 5     var t;
 6 
 7     it('should assign string', function(){
 8         a.strAssign('abcdefg');
 9         expect(a + '').toBe('abcdefg');
10 
11         b.strAssign('hijklmno');
12         expect(b + '').toBe('hijklmno');
13 
14         c.strAssign('abcdefg');
15         expect(c + '').toBe('abcdefg');
16     });
17 
18     it('should compare', function(){
19         expect(a.strCompare(b)).toBe(false);
20         expect(a.strCompare(c)).toBe(true);
21     });
22 
23     it('should concat', function(){
24         t = a.concat(b);
25         expect(t + '').toBe('abcdefghijklmno');
26     });
27 
28     it('should substring', function(){
29         t = t.substring(2, 5);
30         expect(t + '').toBe('cdefg');
31     });
32 });
View Code
相關文章
相關標籤/搜索