1、串类型的定义
串(string)(或字符串)是由零个或多个字符组成的有限序列,一般记为
s = ‘a1a2…an’ (n ≥ 0)
其中,s 是串的名,用单引号括起来的字符序列是串的值;ai(1 ≤ i ≤ n)可以是字母、数字或其它字符;串中字符的数目 n 称为串的长度。零个字符的串称为空串(null string),它的长度为零。
串中任意个连续的字符组成的子序列称为该串的子串。包括子串的串相应地称为主串。通常称子串在序列中的序号为该字符在串中的位置。子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。
称两个串是相等的,当且仅当这两个串的值相等,也就是说,只有当两个串的长度相等,并且各个对应位置的字符都相等。
串值必须用一对单引号括起来,但单引号本身并不属于串,它的作用是为了避免与变量名或数的常量混淆而已。
在各种应用中,空格常常是串的字符集合中的一个元素,因而可以出现在其它字符中间,由一个或多个空格组成的串‘ ’称为空格串(blank string,请注意,此处不是空串)。它的长度为串中空格字符的个数。
对于串的基本操作集可以有不同的定义方法,在使用高级程序设计语言中的串类型时,应以该语言的参考手册为准。
例如,可利用库函数来实现子串的定位,算法如下:
1 String mainString = "Tom Godwin's main string."; 2 String targetString = "Godwin"; 3 // String targetString = "NoString"; 4 5 int pos = mainString.indexOf(targetString); 6 if(pos != -1) 7 { 8 System.out.println("Find the target String at: " + pos); 9 } 10 else 11 { 12 System.out.println("Not found the target string."); 13 }
2、串的表示和实现
1)定长顺序存储表示
在串的定长顺序存储结构中,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储去,则可用定长数组。
串连接可以使用 ‘+’ 来实现:
System.out.println("The concat string is: " + (mainString + targetString));
求子串可以通过 substring 函数实现:
System.out.println("Ths SubString is: " + mainString.substring(4, 12));
2)栈分配存储表示
这种存储表示的特点是,仍以一组地址连续的存储单元存放串值字符序列,但它们的存储空间是在程序执行过程中动态分配的。
串的比较可以通过 mainString.compareTo(targetString) 来实现,函数返回字符串中第一个字母 ASCII 的差值。
3)串的块链存储表示
由于串结构中的每个数据元素是一个字符,则用链表结构存储串值是,存在一个“节点大小”的问题。即每个节点可以存放一个字符,也可以存放多个字符。为了便于进行串操作,当以链表存储串值时,除头指针外还可以附设一个尾指针表示链表中的最后一个节点,并给出当前串的长度,称如此定义的串存储结构为块链结构。
3、串的模式匹配算法
1)求子串位置的定位函数 Index(S,T,pos)
子串的定位操作通常称为串的模式匹配(其中 T 称为模式串)。算法如下:
1 public static int myIndex(String ms, String ts, int pos) 2 { 3 int i = pos; 4 int j = 0; 5 6 while(i < ms.length() && j < ts.length()) 7 { 8 if(ms.charAt(i) == ts.charAt(j)) 9 { 10 i++; 11 j++; 12 } 13 else 14 { 15 i = i - j + 1; 16 j = 0; 17 } 18 } 19 20 if(j >= ts.length()) 21 { 22 return i - ts.length(); 23 } 24 else 25 { 26 return -1; 27 } 28 }
2)模式匹配的一种改进算法
这种改进算法是 D.E.Knuth 与 V.R.Pratt 和 J.H.Morris 同时发现的,因此称为 KMP 算法。其中的改进在于:每当一趟匹配过程中出现字符比较不等时,不需回溯 i 指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
依照 KMP 算法,可以得到 next 函数的算法,同时进行了优化:
1 public static void getNext(String ts, int[] nextval) 2 { 3 int i = 0; 4 nextval[0] = -1; 5 int j = -1; 6 7 while(i < ts.length() - 1) 8 { 9 if(j == -1) 10 { 11 i++; 12 j++; 13 if(ts.charAt(i) != ts.charAt(j)) 14 nextval[i] = j; 15 else 16 nextval[i] = nextval[j]; 17 } 18 else if(ts.charAt(i) == ts.charAt(j)) 19 { 20 i++; 21 j++; 22 if(ts.charAt(i) != ts.charAt(j)) 23 nextval[i] = j; 24 else 25 nextval[i] = nextval[j]; 26 } 27 else 28 { 29 j = nextval[j]; 30 } 31 } 32 }
注:由于使用了字符串变量,对原算法中的标志设置进行了调整:
(1)原算符有效数据从1开始,字符串变量的有效数据从1开始,标志的终止值以及递增的基准值,都进行了相应的调整;
(2)字符串变量的下限为0,所以把判断时的条件拆分,以避免出现异常;
KMP 算法如下:
1 public static int index_KMP(String ms, String ts, int pos, int next[]) 2 { 3 int loc = -1; 4 int i = pos -1; 5 int j = -1; 6 7 while((i <= ms.length() -1) && (j <= ts.length() - 1)) 8 { 9 if(j == -1) 10 { 11 i++; 12 j++; 13 } 14 else if(ms.charAt(i) == ts.charAt(j)) 15 { 16 i++; 17 j++; 18 } 19 else 20 { 21 j = next[j]; 22 } 23 } 24 25 if(j >= ts.length()) 26 { 27 loc = i - ts.length(); 28 } 29 30 return loc; 31 }
End