数据结构快速学习--02字符串
字符串可以说是我们实际工作中使用最多的数据类型了,常见的字符串操作包括链接、取子串、格式化等。这部分内容总体来说比较容易理解,最难的部分要数字符串的模式匹配方法了,尤其是KMP算法,需要通过实践加以记忆。
串的定义:是由零个或者多个字符组成的有限序列,又叫字符串。串的比较是通过其编码的顺序进行的(对于ASCII码来说,其通过7个二进制表示一个字符,共可以表示128个字符),通常来说,对于给定的两个字符串s=a1a2…an,t=b1b2…bm来说,如果n<m且ai=bi(i=1,2…n),那么有s<t;如果存在某个k<=min(m,n),使得ai=bi(i=1,2…k-1),ak<bk,则s<t。接下来通过一个表格来了解串的常见操作(用C#自定义字符串类实现)。
操作 |
诠释 |
---|---|
StrAssign(T, *chars) |
生成一个其值等于字符串常量chars的串T |
StrCopy(T,S) |
串S存在,由串S复制得到T |
ClearString(S) |
若S存在,将串清空 |
StringEmpty(S) |
若S存在,返回true,否则返回false |
StrLength(S) |
返回串S的元素个数,即串的长度 |
StrCompare(S,T) |
若S>T返回值>0,若相等返回0,若S<T的返回值<0 |
Concat(T,S1,S2) |
用T返回由S1和S2联结成的新串 |
SubString(Sub,S,pos,len) |
若串存在,1<=pos<=StrLength(S),且0<=lenStrLength(S)-pos+1, 用Sub返回串S的第pos个字符起长度为len的子串。 |
Index(S,T,pos) |
串S和T存在,T是非空串,1<=pos<=StrLength(S) 若主串S中存在和串T相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置,否则返回0。 |
Replace(S,T,V) |
串S,T,V存在,T是非空串,用V替换主串S中出现的所有与T相等的不重叠的子串 |
StrInsert(S,pos,T) |
串S和T存在,1<=pos<=StrLength(S)+1 在串S的第pos个字符前插入串T |
StrDelete(S,pos,len) |
串S存在,1<=pos<=StrLength(S)-len+1 从串S中删除第pos个字符起长度为len的子串 |
串的存储结构:通常来说,串都是使用顺序存储结构来实现的,链式的存储结构不太适合串。串的顺序存储是由一组地址连续的存储单元来存储串中的字符序列的,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,一般用定长数组实现,用'n'来表示一个串值得终结。
串的实现,如下所示,使用javascript编写,依赖于数组方法。
1 //////////////////////////////////////基础部分///////////////////////////////////////////////////////////
2
3 function MyString(strArray) {
4 //均需依赖于数组的操作
5 this.strArray = strArray;
6 this.strCopy = function() {
7 var newString = new MyString();
8 newString.strArray = this.strArray.slice();
9 return newString;
10 }
11 this.clearString = function() {
12 this.strArray = [];
13 }
14
15 this.stringEmpty = function() {
16 if (this.strLength() == 0) {
17 return true;
18 }
19 return false;
20 }
21 this.strLength = function() {
22 return this.strArray.length;
23 }
24
25 this.strCompare = function(otherStrArray) {
26 var compareLength = Math.min(this.strLength(), otherStrArray.length);
27 var i;
28 for (i = 0; i < compareLength; i++) {
29 if (this.strArray[i] != otherStrArray[i]) {
30 break;
31 }
32 }
33
34 if (this.strArray[i] > otherStrArray[i]) {
35 return 1;
36 } else if (this.strArray[i] == otherStrArray[i]) {
37 return 0;
38 } else {
39 return -1;
40 }
41 }
42
43 this.concat = function(otherStrArray) {
44 var newString = new MyString();
45 newString.strArray = this.strArray.concat(otherStrArray);
46 return newString;
47 }
48 this.subString = function(pos, len) {
49 if (pos >= 0 && len >= 0 && pos + len < this.strLength()) {
50 var newString = new MyString();
51 newString.strArray = this.strArray.slice(pos, pos + len);
52 return newString;
53 }
54 }
55 this.index = function(subStrArray, pos) {
56 if (pos < 0 || subStrArray.length > this.strLength() || pos >= this.strLength() - subStrArray.length) {
57 return -1;
58 }
59 for (var i = pos; i < this.strLength(); i++) {
60 var tempI = i;
61 for (j = 0; j < subStrArray.length; j++) {
62 if (subStrArray[j] != this.strArray[tempI]) {
63 break;
64 }
65 tempI++;
66 }
67 // console.log(tempI);
68 if (tempI == i + subStrArray.length) {
69 return i - pos;
70 }
71 // console.log(i);
72 }
73 return -1;
74 }
75
76 this.replace = function(originalSubStrArray, targetSubStrArray) {
77 //需要依赖于index方法
78 var pos = this.index(originalSubStrArray, 0);
79 this.strDelete(pos, originalSubStrArray.length);
80 this.strInsert(pos, targetSubStrArray);
81 }
82
83 this.strInsert = function(pos, subStrArray) {
84 if (pos >= 0 && pos <= this.strLength()) {
85 var partA = this.strArray.slice(0, pos);
86 var partB = this.strArray.splice(pos, this.strLength());
87 this.strArray = partA.concat(subStrArray, partB);
88 }
89 }
90
91 this.strDelete = function(pos, len) {
92 if (pos >= 0 && len >= 0 && pos + len <= this.strLength()) {
93 var partA = this.strArray.slice(0, pos);
94 var partB = this.strArray.splice(pos + len, this.strLength());
95 this.strArray = partA.concat(partB);
96 }
97 }
98 }
99 }
100
101 //////////////////////////////////////测试部分///////////////////////////////////////////////////////////
102 var strArray = ['x', 'i', 'o', 'n', 'g', 'e', 'r'];
103 var otherStrArray = ['x', 'i', 'o', 'n', 'g', 'e', 'r'];
104 var tempStrArray = ['n', 'g'];
105 var replaceStrArray = ['t', 't'];
106
107 var str = new MyString(strArray);
108 console.log(str);
109 var newStr = str.strCopy();
110 console.log(newStr);
111 console.log(newStr == str);
112 console.log(newStr === str);
113 console.log(newStr.strCompare(otherStrArray));
114
115 newStr = str.concat(otherStrArray);
116 console.log(newStr);
117 // var strArray = 'xionger'.split('');
118 // console.log(strArray);
119 // console.log(strArray.length);
120 newStr = str.subString(2, 2);
121 console.log(newStr);
122
123 // str.strDelete(4, 2);
124 // console.log(str);
125 // str.strInsert(7, tempStrArray);
126 // console.log(str);
127 var index = str.index(tempStrArray, 2);
128 console.log(index);
129
130 // str.replace(tempStrArray, replaceStrArray);
131 // console.log(str);
KMP模式匹配算法:可以看到之前的朴素模式匹配算法的时间复杂度为O(n2),效率比较低下,因此更合适的方式是由Knuth,Morris,Pratt三位科学家研究的模式匹配算法,可以大大的减少重复遍历的情况。在之前的朴素模式匹配的算法中存在两个嵌套的循环,外部循环不存在回溯,但存在重复比较,内部循环存在回溯。因此,可以想到的优化点就是内外循环的变量值得设置。这部分用文字表述将非常的复杂且不容易理解,接下来通过代码让我们来熟悉这部分知识,也是本文最难的部分。
借用博文http://www.cnblogs.com/c-cloud/p/3224788.html的解释,非常准确,有空时可以继续深入学习。
参考资料:
- 程杰. 大话数据结构[M]. 北京:清华大学出版社, 2011.
- 严蔚敏, 吴伟民. 数据结构(C语言版)[M]. 北京:清华大学出版社, 2004.
- Asp.Net4.0/VS2010新变化(4):SEO的改进
- Pandas DataFrame笔记
- 让控件填满整个页面
- 用多个类别来进行微调
- Asp.Net4.0/VS2010新变化(2):网站自动预热
- Asp.Net4.0/VS2010新变化(1):web.config与publish
- 任天堂将推出Nintendo Labo 域名保护意识墙
- 表格效果
- ROR学习笔记(2):Asp.Net开发者看ROR
- 图片的javascript延时加载
- 全世界最短IE判定if(!+[1,])的解释
- Log4Net与Log2Console配合时中文问题的解决
- 如何改变AspNetPager当前页码的默认红色?
- Flash/Flex学习笔记(48):反向运动学(下)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- TKE集群pod镜像拉取失败定位思路
- Android内存管理(JVM 、DVM(dalvik) 、ART简单介绍)
- WordPress 站点地址被恶意篡改的防护方案讨论
- 猿实战06——不一样的地址管理
- Redis常用命令详解
- three.js 制作逻辑转体游戏(下)
- ROS机器人TF基础(坐标相关概念和实践)
- (在模仿中精进数据可视化01) 全国38城居住自由指数可视化
- js字符串/数组常用方法总结
- ThinkPHP5+mpdf 实现富文本生成 PDF文件
- nodejs使用readline逐行读取和写入文件
- go语言逐行读取和写入文件
- SpringBoot中Tomcat是如何启动的
- 自定义注解详解及应用
- 微服务开源框架TARS 之 框架服务解析