概述
一、基本概念
1、定义
串( string)是由零个或多个字符组成的有限序列,又名叫字符串。
S='a1a2...an';
S为串名,n为串的长度
A='ABCD';
B='ABCDEF';
A!=B;
A∈B;
当两个串的值相等时,这两个串才相等
2、串分类
-
子串:串中任意个连续的字符组成的子序列车称为该串的子串,子串在主串中的位置就是子串的第一个字符在主串中的序号。
-
主串:包含子串的串称为主串
-
串值:必须用单引号括起来,但单引号不属于串,它的作用只为了避免与变量名或数的常量混淆
-
空串: n = 0 n=0 n=0时的串称为空串。
-
空格串:是由一个或多个空格组成的串,但不是空串,长度为串中空格字符的个数,用“ø”表示。注意它与空串的区别,空格串是有内容有长度的,而且可以不止一个空格。
-
子串与主串:串中任意个数的连续字符组成的子序列称为该串的子串,相应地,包含子串的串称为主串。
二、串的存储结构
1、定长顺序存储表示
类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的定长顺序存储结构中,为每个串变量分配一个固定长度的存储区,即定长数组。
#define MAXLEN 255; //预定义最大串长为255
typedef struct{
char ch[MAXLEN]; //每个分量存储一个字符
int length; //串的实际长度
}SString;
串的实际长度只能小于等于MAXLEN,超过预定义长度的串值会被舍去,称为截断。串长有两种表示方法: 一是如上述定义描述的那样,用一个额外的变量len来存放串的长度;二是在串值后面加一一个不计入串长的结束标记字符“ ”,此时的串长为隐含值。
在一些串的操作(如插入、联接等)中,若串值序列的长度超过上界MAXLEN,约定用“截断”法处理,要克服这种弊端,只能不限定串长的最大长度,即采用动态分配的方式。
2、堆分配存储表示
堆分配存储表示仍然以一组地址连续的存储单元存放串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。
typedef struct{
char *ch; //按串长分配存储区,ch指向串的基地址
int length; //串的长度
}HString;
3、块链存储表示
类似于线性表的链式存储结构,也可采用链表方式存储串值。由于串的特殊性(每个元素只有一个字符),在具体实现时,每个结点既可以存放一个字符, 也可以存放多个字符。每个结点称为块,整个链表称为块链结构。图(a)是结点大小为4 (即每个结点存放4个字符)的链表,最后一个结点占不满时通常用“#”补上;图(b)是结点大小为1的链表。
三、串的基本操作
-
StrAssign(&T, chars): 赋值操作。把串T赋值为 chars
-
Strcopy(&TS): 复制操作。由串S复制得到串T。
-
StrEmpty(S): 判空操作。若S为空串,则返回TRUE,否则返回 FALSE
-
StrCompare(S,T): 比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。
-
StrEngth(S): 求串长。返回串S的元素个数
-
Substring(&Sub,S,pos,1en):求子串。用Sub返回串S的第pos个字符起长度为len的子串。
-
Concat(&T,S1,S2): 串联接。用T返回由S1和S2联接而成的新串。
-
Index(S,T): 定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0
-
Clearstring(&S): 清空操作。将S清为空串
-
Destroystring(&S): 销毁串。将串S销毁
#include <stdio.h>
#include <malloc.h>
typedef struct {
char *ch; //若串是非空串,则按串长度分配存储区,否则ch为NULL
int length; //串长度
}HString;
typedef int Status; //用Status来代替int类型
Status StrAssign(HString &T,char *chars){
//生成一个其值等于串常量chars的串T
int i;
if (T.ch)free(T.ch) //释放T原有空间
for (i = 0; c = chars; *c; ++i; =, ++c); //求chars的长度i
if (!i) { T.ch = NULL; T.ch = 0; }
else {
if (!(T.ch = (char * )malloc(i * sizeof(char))))exit(OVERFLOW);
T.ch[0..i - 1] = chars[0..i - 1];
T.length = i;
}
return OK;
}
int Strlength(HString S) {
//返回S的元素个数,称为串的长度
return S.length;
}
int StrCompare(HString S, HString T){
//若S>T,则返回值>0;若S=T,则返回值=0;若S<T;则返回值<0;
int i;
for (i = 0; i < S.length && i < T.length; ++i)
if (S.ch[i] != T.ch[i])return S.ch[i] - T.ch[i];
return S.length - T.length;
}
Status ClearString(HString &S){
//将S清为空串,并释放S所占的空间
if (S.ch) { free(S.ch); S.ch = NULL; }
S.length = 0;
return OK;
}
Status Concat(HString &T, HString S1, HString S2){
//用T返回由S1和S2联接而成的新串
if (T.ch)free(T.ch); //释放旧空间
if (!(T.ch = (char*)malloc((S1.length + S2.length) * sizeof(char))))exit(OVERFLOW);
T.ch[0..S1.length - 1] = S1.ch[0..S1.length - 1];
T.length = S1.length + S2.length;
T.ch[S1.length..T.length - 1] = S2.ch[0..S2.lenth - 1];
return OK;
}
HString SubString(HString S,int pos,int len){
//1<=pos<=StrLength(S)且0<=len<=StrLength(S)-pos+1
//返回串S的第pos个字符起长度为len的子串
if (pos<1 || pos>S.length || len<0 || len>S.length - pos - 1)
return ERROR;
if (Sub.ch)free(Sub.ch); //释放旧空间
if (!len) { Sub.ch = null; Sub.length = 0; } //空子串
else { //完整子串
Sub.ch = (char * )malloc(len * sizeof(char));
Sub.ch[0..len - 1] = S.ch[pos - 1..pos + len - 2];
Sub.length = len;
}
return OK;
}
五、串的匹配模式
1、简单的模式匹配算法
子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。这里采用定长顺序存储结构,给出一种不依赖于其他串操作的暴力匹配算法。
int Index(SString S, SString T){
int i = 1, j = 1;
while(i <= S.length && j <= T.length){
if(S.ch[i] == T.ch[j]){
++i; ++j; //继续比较后继字符
}else{
//指针后退重新开始匹配
i = i-j+2;
j = 1;
}
}
if(j > T.length){
return i - T.length;
}else{
return 0;
}
}
2、KMP算法
KMP算法的特点就是:仅仅后移模式串,比较指针不回溯
最后
以上就是含蓄纸鹤为你收集整理的数据结构——(4)、串一、基本概念三、串的基本操作五、串的匹配模式的全部内容,希望文章能够帮你解决数据结构——(4)、串一、基本概念三、串的基本操作五、串的匹配模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复