知识给人重量,成就给人光彩,大多数人只是看到了光彩,而不去称量重量
字符串、简称串,它也是一种重要的线性结构。计算机中处理的大部分数据都是字符串数据,例如,学生学籍信息系统的姓名、性别、家庭住址、院系名称等信息都属于字符串数据。串广泛应用于各种专业的信息管理、信息检索、问答系统、机器翻译等系统处理中。
一、顺序串的基本操作:
stringAssign () 初始化串 stringCopy () 串的拷贝 getLength () 获取串的长度 stringClear() 清空串 subString() 求子串 stringCompare() 串的比较 stringInsert() 串的插入 stringConcat() 串的连接 getNextVal() 获取每个字符的下一个匹配开始点 KMP_Index() KMP 模式匹配算法 stringDelete() 串的删除(用到模式匹配算法,这里使用KMP算法) stringReplace() 子串替换,只替换第一个子串 stringPrint() 打印串
1.1 基本操作代码实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1;
#define FALSE 0;
#define OK 1;
#define ERROR 0;
#define MAX_NUM 100
#define Status int
typedef struct {
char ch
[MAX_NUM
+1];
int length
;
}String
;
void stringAssign(String
*str
, char *chars
){
if (str
== NULL) exit(0);
int len
= strlen(chars
);
str
->length
= len
;
for (int i
= 0; i
< len
; ++i
) {
str
->ch
[i
] = chars
[i
];
}
}
void stringCopy(String
*str
, String
*str_
){
for (int i
= 0; i
< str_
->length
; ++i
) {
str
->ch
[i
] = str_
->ch
[i
];
}
str
->length
= str_
->length
;
}
int getLength(String
*str
){
return str
->length
;
}
void stringStr(String
*str
){
str
->length
= 0;
}
Status
subString(String
*str
, String
*sonStr
, int pos
, int len
){
if (pos
< 0 || len
< 1 || pos
>=str
->length
|| pos
+len
> str
->length
) return FALSE
;
for (int i
= pos
; i
< pos
+len
; ++i
) {
sonStr
->ch
[i
-pos
] = str
->ch
[i
];
}
sonStr
->length
= len
;
return TRUE
;
}
int stringCompare(String
*str
, String
*compareStr
){
for (int i
= 0; i
<str
->length
&& i
< compareStr
->length
; ++i
) {
if (str
->ch
[i
] != compareStr
->ch
[i
]) {
return str
->ch
[i
] - compareStr
->ch
[i
];
}
}
return str
->length
- compareStr
->length
;
}
Status
stringInsert(String
*str
, int pos
, String
*insertStr
){
if (str
== NULL && insertStr
== NULL) return ERROR
;
if (pos
< 0 || pos
> str
->length
|| pos
+insertStr
->length
> MAX_NUM
) return ERROR
;
for (int i
= str
->length
-1 ; i
>= pos
; --i
) {
str
->ch
[i
+insertStr
->length
] = str
->ch
[i
];
}
for (int j
= 0; j
< insertStr
->length
; ++j
) {
str
->ch
[j
+pos
] = insertStr
->ch
[j
];
}
str
->length
+= insertStr
->length
;
return OK
;
}
Status
stringConcat(String
*str
, String
*conStr
){
if (str
== NULL && conStr
== NULL) return ERROR
;
for (int i
= 0; i
< conStr
->length
; ++i
) {
str
->ch
[str
->length
+i
] = conStr
->ch
[i
];
}
str
->length
+= conStr
->length
;
return TRUE
;
}
int getNextVal(int next
[], String
*T
) {
int j
= 0, k
=-1;
next
[0] = -1;
while (j
< T
->length
-1) {
if (k
== -1 || T
->ch
[j
] == T
->ch
[k
]) {
j
++;
k
++;
if (T
->ch
[j
] == T
->ch
[k
])
next
[j
] = next
[k
];
else
next
[j
] = k
;
} else k
= next
[k
];
}
}
int KMP_Index(String
*str
, String
*T
){
int next
[T
->length
],i
=0,j
=0;
getNextVal(next
,T
);
while (i
< str
->length
&& j
< T
->length
) {
if (j
== -1 || str
->ch
[i
] == T
->ch
[j
]) {
i
++;
j
++;
} else j
= next
[j
];
}
if (j
>= T
->length
) {
return (i
- T
->length
);
} else return -1;
}
Status
stringDelete(String
*str
, String
*deleteStr
){
if (str
== NULL && deleteStr
== NULL) return ERROR
;
if (deleteStr
->length
> str
->length
) return ERROR
;
int index
= KMP_Index(str
,deleteStr
);
if (index
< 0) {
return FALSE
;
}
for (int i
= index
; i
< str
->length
-deleteStr
->length
; ++i
) {
str
->ch
[i
] = str
->ch
[i
+deleteStr
->length
];
}
str
->length
-= deleteStr
->length
;
return TRUE
;
}
Status
stringReplace(String
*str
, String
*T
, String
*reStr
){
if (str
== NULL || T
== NULL|| reStr
== NULL) return FALSE
;
int index
= KMP_Index(str
, T
);
stringDelete(str
,T
);
return stringInsert(str
,index
,reStr
);
}
void stringPrint(String
*str
){
for (int i
= 0; i
< getLength(str
); ++i
) {
printf("%c",str
->ch
[i
]);
}
printf("\n");
}
int main(){
String str
, str_
, sonStr
, comStr
, deStr
,reStr
, conStr
;
int pos
= 1, len
= 3;
char *chars
= "I Love China!";
char *chars_
= "China nb China nb!";
char *comChars
= "China is the best in the world!";
char *reChars
= "66";
char *deChars
= "in";
char *conChars
= "China is the best";
stringAssign(&str
, chars
);
printf("str初始化:");
stringPrint(&str
);
printf("----------------------\n");
stringAssign(&str_
, chars_
);
printf("str_初始化:");
stringPrint(&str_
);
printf("======================\n");
int strLen
= getLength(&str
);
printf("str串的长度为:%d\n", strLen
);
printf("======================\n");
stringCopy(&str
, &str_
);
printf("str 拷贝 str_ : ");
stringPrint(&str
);
printf("======================\n");
subString(&str
,&sonStr
, pos
, len
);
printf("求子串 第 1 个字符起到长度为 3 的子串(不含第一个本身):");
stringPrint(&sonStr
);
printf("======================\n");
stringAssign(&comStr
, comChars
);
printf("str 与 comStr 比较: ");
int result
= stringCompare(&str
, &comStr
);
if (result
> 0) {
printf("str 大\n");
}else if (result
== 0) {
printf("两者相等\n");
}else {
printf("comStr 大\n");
}
printf("======================\n");
stringAssign(&reStr
,reChars
);
stringAssign(&deStr
, deChars
);
stringReplace(&str
,&deStr
,&reStr
);
printf("替换 in 子串 为 666(只替换第一个):");
stringPrint(&str
);
printf("======================\n");
int index
= KMP_Index(&str
,&deStr
);
printf("KMP 模式匹配算法,求子串 in 的位置:%d\n", index
);
printf("======================\n");
stringDelete(&str
, &deStr
);
printf("删除子串 in: ");
stringPrint(&str
);
printf("======================\n");
stringAssign(&conStr
, conChars
);
stringConcat(&str
, &conStr
);
printf("str 与 constr 进行拼接:");
stringPrint(&str
);
return 0;
}
1.2 KMP算法实现原理:
可跳转至此篇博文,讲的非常好 —> KMP算法—终于全部弄懂了
二、 串的块链存储表示:
串结构的特殊性------结构中的每个数据元素是一个字符,则用链表存储串值时,存在一个“结点大小”的问题,即每个结点可以存放一个字符,也可以存放多个字符。
基本操作实现:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define CHUNKSIZE 80
char blank
='#';
typedef int Status
;
typedef struct Chunk
{
char ch
[CHUNKSIZE
];
struct Chunk
*next
;
}Chunk
;
typedef struct
{
Chunk
*head
, *tail
;
int curlen
;
}LString
;
void InitString(LString
*T
)
{
(*T
).curlen
=0;
(*T
).head
=NULL;
(*T
).tail
=NULL;
}
Status
StrAssign(LString
*T
,char *chars
)
{
int i
,j
,k
,l
;
Chunk
*p
,*q
;
i
=strlen(chars
);
if(!i
|| strchr(chars
,blank
))
return ERROR
;
(*T
).curlen
=i
;
j
=i
/CHUNKSIZE
;
if(i
%CHUNKSIZE
)
j
++;
for(k
=0;k
<j
;k
++)
{
p
=(Chunk
*)malloc(sizeof(Chunk
));
if(!p
)
return ERROR
;
if(k
==0)
(*T
).head
=q
=p
;
else
{
q
->next
=p
;
q
=p
;
}
for(l
=0;l
<CHUNKSIZE
&&*chars
;l
++)
*(q
->ch
+l
)=*chars
++;
if(!*chars
)
{
(*T
).tail
=q
;
q
->next
=NULL;
for(;l
<CHUNKSIZE
;l
++)
*(q
->ch
+l
)=blank
;
}
}
return OK
;
}
Status
StrCopy(LString
*T
,LString S
)
{
Chunk
*h
=S
.head
,*p
,*q
;
(*T
).curlen
=S
.curlen
;
if(h
)
{
p
=(*T
).head
=(Chunk
*)malloc(sizeof(Chunk
));
*p
=*h
;
h
=h
->next
;
while(h
)
{
q
=p
;
p
=(Chunk
*)malloc(sizeof(Chunk
));
q
->next
=p
;
*p
=*h
;
h
=h
->next
;
}
p
->next
=NULL;
(*T
).tail
=p
;
return OK
;
}
else
return ERROR
;
}
Status
StrEmpty(LString S
)
{
if(S
.curlen
)
return FALSE
;
else
return TRUE
;
}
int StrCompare(LString S
,LString T
)
{
int i
=0;
Chunk
*ps
=S
.head
,*pt
=T
.head
;
int js
=0,jt
=0;
while(i
<S
.curlen
&&i
<T
.curlen
)
{
i
++;
while(*(ps
->ch
+js
)==blank
)
{
js
++;
if(js
==CHUNKSIZE
)
{
ps
=ps
->next
;
js
=0;
}
};
while(*(pt
->ch
+jt
)==blank
)
{
jt
++;
if(jt
==CHUNKSIZE
)
{
pt
=pt
->next
;
jt
=0;
}
};
if(*(ps
->ch
+js
)!=*(pt
->ch
+jt
))
return *(ps
->ch
+js
)-*(pt
->ch
+jt
);
else
{
js
++;
if(js
==CHUNKSIZE
)
{
ps
=ps
->next
;
js
=0;
}
jt
++;
if(jt
==CHUNKSIZE
)
{
pt
=pt
->next
;
jt
=0;
}
}
}
return S
.curlen
-T
.curlen
;
}
int StrLength(LString S
)
{
return S
.curlen
;
}
Status
ClearString(LString
*S
)
{
Chunk
*p
,*q
;
p
=(*S
).head
;
while(p
)
{
q
=p
->next
;
free(p
);
p
=q
;
}
(*S
).head
=NULL;
(*S
).tail
=NULL;
(*S
).curlen
=0;
return OK
;
}
Status
Concat(LString
*T
,LString S1
,LString S2
)
{
LString a1
,a2
;
InitString(&a1
);
InitString(&a2
);
StrCopy(&a1
,S1
);
StrCopy(&a2
,S2
);
(*T
).curlen
=S1
.curlen
+S2
.curlen
;
(*T
).head
=a1
.head
;
a1
.tail
->next
=a2
.head
;
(*T
).tail
=a2
.tail
;
return OK
;
}
Status
SubString(LString
*Sub
, LString S
,int pos
,int len
)
{
Chunk
*p
,*q
;
int i
,k
,n
,flag
=1;
if(pos
<1||pos
>S
.curlen
||len
<0||len
>S
.curlen
-pos
+1)
return ERROR
;
n
=len
/CHUNKSIZE
;
if(len
%CHUNKSIZE
)
n
++;
p
=(Chunk
*)malloc(sizeof(Chunk
));
(*Sub
).head
=p
;
for(i
=1;i
<n
;i
++)
{
q
=(Chunk
*)malloc(sizeof(Chunk
));
p
->next
=q
;
p
=q
;
}
p
->next
=NULL;
(*Sub
).tail
=p
;
(*Sub
).curlen
=len
;
for(i
=len
%CHUNKSIZE
;i
<CHUNKSIZE
;i
++)
*(p
->ch
+i
)=blank
;
q
=(*Sub
).head
;
i
=0;
p
=S
.head
;
n
=0;
while(flag
)
{
for(k
=0;k
<CHUNKSIZE
;k
++)
if(*(p
->ch
+k
)!=blank
)
{
n
++;
if(n
>=pos
&&n
<=pos
+len
-1)
{
if(i
==CHUNKSIZE
)
{
q
=q
->next
;
i
=0;
}
*(q
->ch
+i
)=*(p
->ch
+k
);
i
++;
if(n
==pos
+len
-1)
{
flag
=0;
break;
}
}
}
p
=p
->next
;
}
return OK
;
}
int Index(LString S
,LString T
,int pos
)
{
int i
,n
,m
;
LString sub
;
if(pos
>=1&&pos
<=StrLength(S
))
{
n
=StrLength(S
);
m
=StrLength(T
);
i
=pos
;
while(i
<=n
-m
+1)
{
SubString(&sub
,S
,i
,m
);
if(StrCompare(sub
,T
)!=0)
++i
;
else
return i
;
}
}
return 0;
}
void Zip(LString
*S
)
{
int j
,n
=0;
Chunk
*h
=(*S
).head
;
char *q
;
q
=(char*)malloc(((*S
).curlen
+1)*sizeof(char));
while(h
)
{
for(j
=0;j
<CHUNKSIZE
;j
++)
if(*(h
->ch
+j
)!=blank
)
{
*(q
+n
)=*(h
->ch
+j
);
n
++;
}
h
=h
->next
;
}
*(q
+n
)=0;
ClearString(S
);
StrAssign(S
,q
);
}
Status
StrInsert(LString
*S
,int pos
,LString T
)
{
int i
,j
,k
;
Chunk
*p
,*q
;
LString t
;
if(pos
<1||pos
>StrLength(*S
)+1)
return ERROR
;
StrCopy(&t
,T
);
Zip(S
);
i
=(pos
-1)/CHUNKSIZE
;
j
=(pos
-1)%CHUNKSIZE
;
p
=(*S
).head
;
if(pos
==1)
{
t
.tail
->next
=(*S
).head
;
(*S
).head
=t
.head
;
}
else if(j
==0)
{
for(k
=1;k
<i
;k
++)
p
=p
->next
;
q
=p
->next
;
p
->next
=t
.head
;
t
.tail
->next
=q
;
if(q
==NULL)
(*S
).tail
=t
.tail
;
}
else
{
for(k
=1;k
<=i
;k
++)
p
=p
->next
;
q
=(Chunk
*)malloc(sizeof(Chunk
));
for(i
=0;i
<j
;i
++)
*(q
->ch
+i
)=blank
;
for(i
=j
;i
<CHUNKSIZE
;i
++)
{
*(q
->ch
+i
)=*(p
->ch
+i
);
*(p
->ch
+i
)=blank
;
}
q
->next
=p
->next
;
p
->next
=t
.head
;
t
.tail
->next
=q
;
}
(*S
).curlen
+=t
.curlen
;
Zip(S
);
return OK
;
}
Status
StrDelete(LString
*S
,int pos
,int len
)
{
int i
=1;
Chunk
*p
=(*S
).head
;
int j
=0;
if(pos
<1||pos
>(*S
).curlen
-len
+1||len
<0)
return ERROR
;
while(i
<pos
)
{
while(*(p
->ch
+j
)==blank
)
{
j
++;
if(j
==CHUNKSIZE
)
{
p
=p
->next
;
j
=0;
}
}
i
++;
j
++;
if(j
==CHUNKSIZE
)
{
p
=p
->next
;
j
=0;
}
};
while(i
<pos
+len
)
{
while(*(p
->ch
+j
)==blank
)
{
j
++;
if(j
==CHUNKSIZE
)
{
p
=p
->next
;
j
=0;
}
}
*(p
->ch
+j
)=blank
;
i
++;
j
++;
if(j
==CHUNKSIZE
)
{
p
=p
->next
;
j
=0;
}
};
(*S
).curlen
-=len
;
return OK
;
}
Status
Replace(LString
*S
,LString T
,LString V
)
{
int i
=1;
if(StrEmpty(T
))
return ERROR
;
do
{
i
=Index(*S
,T
,i
);
if(i
)
{
StrDelete(S
,i
,StrLength(T
));
StrInsert(S
,i
,V
);
i
+=StrLength(V
);
}
}while(i
);
return OK
;
}
void StrPrint(LString T
)
{
int i
=0,j
;
Chunk
*h
;
h
=T
.head
;
while(i
<T
.curlen
)
{
for(j
=0;j
<CHUNKSIZE
;j
++)
if(*(h
->ch
+j
)!=blank
)
{
printf("%c",*(h
->ch
+j
));
i
++;
}
h
=h
->next
;
}
printf("\n");
}
void DestroyString()
{
}
int main()
{
char *s1
="ABCDEFGHI", *s2
="12345", *s3
="", *s4
="asd#tr", *s5
="ABCD";
Status k
;
int pos
,len
;
LString t1
,t2
,t3
,t4
;
InitString(&t1
);
InitString(&t2
);
printf("===============分隔符=========================\n");
printf("初始化串t1后,串t1空否?%d (1:空 0:否) 串长=%d\n",StrEmpty(t1
),StrLength(t1
));
k
=StrAssign(&t1
,s3
);
if(k
==OK
)
{
printf("s3赋值给串t1为: \n");
StrPrint(t1
);
}
else
printf("s3赋值给串t1出错\n");
k
=StrAssign(&t1
,s4
);
if(k
==OK
)
{
printf("s4赋值给串t1为: \n");
StrPrint(t1
);
}
else
printf("s4赋值给串t1出错\n");
k
=StrAssign(&t1
,s1
);
if(k
==OK
)
{
printf("s1赋值给串t1为: ");
StrPrint(t1
);
}
else
printf("s1赋值给串t1出错\n");
printf("串t1空否?%d(1:空 0:否) 串长=%d\n",StrEmpty(t1
),StrLength(t1
));
printf("初始化s2赋值给t2。\n");
StrAssign(&t2
,s2
);
printf("串t2为: ");
StrPrint(t2
);
StrCopy(&t3
,t1
);
printf("由串t1拷贝得到串t3,串t3为: ");
StrPrint(t3
);
InitString(&t4
);
printf("初始化s5赋值给t4。\n");
StrAssign(&t4
,s5
);
printf("串t4为: ");
StrPrint(t4
);
Replace(&t3
,t4
,t2
);
printf("===============分隔符=========================\n");
printf("用t2取代串t3中的t4串后,串t3为: ");
StrPrint(t3
);
ClearString(&t1
);
printf("===============分隔符=========================\n");
printf("清空串t1后,串t1空否?%d(1:空 0:否) 串长=%d \n",StrEmpty(t1
),StrLength(t1
));
Concat(&t1
,t2
,t3
);
printf("===============分隔符=========================\n");
printf("串t1(=t2+t3)为: ");
StrPrint(t1
);
Zip(&t1
);
printf("去除不必要的占位符后,串t1为: ");
StrPrint(t1
);
pos
=Index(t1
,t3
,1);
printf("pos=%d\n",pos
);
printf("===============分隔符=========================\n");
printf("在串t1的第pos个字符之前插入串t2,请输入pos: ");
scanf("%d",&pos
);
k
=StrInsert(&t1
,pos
,t2
);
if(k
)
{
printf("插入串t2后,串t1为: ");
StrPrint(t1
);
}
else
printf("插入失败!\n");
return 0;
}