《C语言数据结构》严蔚敏,吴伟民版。
上章内容链接:https://blog.csdn.net/daqino1/article/details/88833633
以下内容为串
串或字符串(Sting): 由零个或者多个字符组成的有限序列。
串长度:串中字符的数目n,称为串的长度。
空串:零个字符的串。
子串:串中任意个连续的字符组成的子序列。
主串:包含子串的的串。
空格串(blank string):由一个或多个空格组成的串。
//--------------------------串的抽象数据类型-----------------------------------
ADT String {
// 生成一个其值等于chars的串T
StrAssign(&T, chars);
// 由串S复制得到串T
StrCopy(&T, S);
// 若S为空串,则返回TRUE,否则返回FALSE
StrEmpty(S);
// 若S > T, 则返回值 > 0;若S = T,则返回值 = 0;若S < T,则返回值 < 0
StrCompare(S, T);
// 返回S的元素个数, 即串的长度
StrLength(S);
// 将S清为空串
ClearString(&S);
// 用T返回由S1和S2联接而成的新串
Concat(&T, S1, S2);
// 用Sub返回串S的第pos个字符起长度为len的子串
SubString(&Sub, S, pos, len);
/* 若主串S中存在和串T值相同的子串, 则返回它在主串S中第pos个字符之后第一次出现的位置;否则函数值为0*/
Index(S, T, pos);
// 用V替换主串S中出现的所有与T相等的不重叠的子串
Replace(&S, T, V);
// 在串S的第pos个字符之前插入串T
StrInsert(&S, pos, T);
// 从串S中删除第pos个字符起长度为len的子串
StrDelete(&S, pos, len);
// 串S被销毁
DestroyString(&S);
}
串分三种存储表示:定长顺序存储,堆分配存储,块链存储表示。
块链存储需要考虑存储密度:存储密度 = 串值所占的存储位 / 实际分配的存储位
串的定长顺序存储表示如下:
#define MAXSTRLEN 255 // 用户可在255以内定义最大串长
typedef unsigned char SString[MAXSTRLEN + 1]; // 0号单元存放串的长度
Status Concat(SString &T, SString S1, SString S2) {
// 用T返回由S1和S2联接而成的新串。若未截断,则返回TRUE,否则FALSE
if (S1[0] + S2[0] <= MAXSTRLEN) {
// 未截断
T[1..S1[0]] = S1[1..S1[0]];
T[S1[0] + 1..S1[0] + S2[0]] = S2[1..S2[0]];
T[0] = S1[0] + S2[0];
uncut = TRUE;
} else if (S1[0] < MAXSTRLEN) {
// 截断
T[1..S1[0]] = S1[1..S1[0]];
T[S1[0] + 1..MAXSTRLEN] = S2[1..MAXSTRLEN - S1[0]];
T[0] = MAXSTRLEN;
uncut = FALSE;
} else {
// 截断(仅取S1)
T[1..MAXSTRLEN]] = S1[1..MAXSTRLEN];
// T[0] == S1[0] == MAXSTRLEN
uncut = FALSE;
}
return uncut;
}
Status SubString(SString &Sub, SString S, int pos, int len) {
// 用Sub返回串S的第pos个字符起长度为len的子串
// 其中,1<=pos<=StrLength(S)且0<=len<=StrLength(S)-pos+1
if (pos < 1 || pos > S[0] || len < 0 || len > S[0] - pos + 1) {
return ERROR;
}
Sub[1..len] = S[pos..pos + len + 1];
Sub[0] = len;
return OK;
}
串的堆分配存储表示如下:
//-------------------------------------串的堆分配存储表示----------------------------------------
typedef struct {
char *ch; // 若是非空串,则按串长废品存储区,否则ch为NULL
int length; // 串长度
}HString;
//------------------------------------基本操作的函数原型说明-------------------------------------
// 把字符串T插入到字符串S的pos位置
Status StrInsert(HString &S, int pos, HString T);
// 生成一个其值等于串常亮chars的串T
Status StrAssign(HString &T, char* chars);
// 返回S的元素个数,称为串的长度
int StringLength(HString S);
// 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则`在这里插入代码片`返回值<0
int StrCompare(HString S, HString T);
// 将S清为空串,并释放S所占空间
Status ClearString(HString &S);
// 用T返回由S1和S2联接而成的新串
Status Concat(HString &T, HString S1, HString S2);
// 1<=pos<=StrLength(S)且0<=len<=StrLength(S)-pos+1。返回串S的第pos个字符起长度为len的子串
HString SubString(HString S, int pos, int len);
//-------------------------------------基本操作的算法描述-------------------------------------
Status StrInsert(HString &S, int pos, HString T) {
// 1<=pos<=StrLength(S)+1,在串S的第pos个字符之前插入串T。
if (pos < 1 || pos > S.length + 1) {
// pos不合法
return ERROR;
}
if (T.length) {
// T非空,则重新分配空间,插入T
if (!(S.ch = (char *)realloc(S.ch, (S.length + T.length) * sizeof(char)))) {
exit(OVERFLOW);
}
// 为插入T而腾出位置
for (i = S.length - 1; i >= pos - 1; --i) {
S.ch[i+T.length] = S.ch[i];
}
// 插入
S.ch[pos-1..pos + T.length - 2] = T.ch[0..T.length - 1]
S.length += T.length;
}
return OK;
}
Status StrAssign(HString &T, char *chars) {
// 生成一个其值等于串常量chars的串T
if (T.ch) {
// 释放T原有空间
free(T.ch);
}
// 求chars的长度i
for (i = 0, c = chars; c; ++i, ++c)
if (!i) {
T.ch = NULL;
T.length = 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, HSting T) {
// 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
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清为空串
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.length - 1];
return OK:
}
Status SubString(HString &Sub, HString S, int pos, int len) {
// 用Sub返回串S的第pos个字符起长度为len的子串
// 其中, 1<=pos<=StrLength(S)且0<=len<=StrLength(S) - pos + 1
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[pos-1..pos + len - 2];
Sub.length = len;
}
return OK;
}
//-------------------------------------------串的块链存储表示-----------------------------------
#define CHUNKSIZE 80 // 可有用户定义块的大小
typedef struct Chunk {
char ch[CHUNKSIZE];
struct Chunk *next;
}Chunk;
typedef struct {
Chunk *head, *tail; // 串的头和尾指针
int curlen; // 串的 当前长度
}LString;
串的模式匹配算法如下:
int Index(SString S, SString T, int pos) {
// 返回子串T在主串S中的第pos个字符之后的位置。若不存在,则函数值为0。
// 其中,T非空,1<=pos<=StrLength(S)
i = pos;
j = 1;
while (i <= S[0] && j <= T[0]) {
if (S[i] == T[j]) {
// 继续比较后继字符
++i;
++j;
} else {
// 指针后退,重新开始匹配
i = i -j + 2;
j = 1;
}
}
if (j > T[0]) {
return i - T[0];
} else {
return 0;
}
}
int Index_KMP (SString S, SString T, int pos) {
// 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法
// 其中,T非空, 1<=pos <= StrLength(S)
i = pos;
j = 1;
while (i <= S[0] && j <= T[0]) {
if (j == 0 || S[i] == T[j]) {
// 继续比较后继字符
++i;
++j
} else {
// 模式串向右移动
j = next[j];
}
}
if (j > T[0]) {
// 匹配成功
return i - T[0];
} else {
return 0;
}
}
void get_next(SString T, int &next[]) {
// 求模式串T的next函数值,并存入数组next
i = 1;
next[1] = 0;
j = 0;
while (i < T[0]) {
if (j == 0 || T[i] == T[j]) {
++i;
++j;
next[i] = j;
} else {
j = next[j];
}
}
}
void get_nextval(SString T, int &nextval[]) {
// q求模式串T的next函数修正值,并存入数组nextval
i = 1;
nextval[1] = 0;
j = 0;
while (i < T[0]) {
if (j == 0 || T[i] == T[j]) {
++i;
++j;
if (T[i] != T[j]) {
nextval[i] = j;
} else {
nextval[i] = nextval[j];
}
} else {
j = nextval[j];
}
}
}
串的应用: 文本编辑, 建立词索引
上章内容链接:https://blog.csdn.net/daqino1/article/details/88833633