字符串一般简称为串,在我们的编程中使用非常广泛。
一、串类型的定义
串(string)(或字符串)是由零个或过个字符组成的有限序列。
1.基本概念
串的长度:串中字符的数目
空串:零个字符的串
空格串:串中只有一个空格字符的串
子串:串中任意个连续的字符组成的子序列
二、串的实现
1.串的抽象数据类型
这里介绍的顺序存储的串,这个比较容易理解。下面在String.h头文件中给出串的定义:
#ifndef STRING_H_
#define STRING_H_
#define SIZE 10 //最大串长
typedef struct String
{
char elem[SIZE]; //存放串的数组
int length; //有效串长
}String;
void StrAssign(String *s, const char *chars); //串赋值
void StrCpy(String *dest, const String *src); //串拷贝
bool IsEmpty(const String *s); //判断串是否为空
void Clear(String *s); //清空串
int GetLength(const String *s); //获取串的长度
bool SubString(String *sub, const String *s, int pos, int len);//获取子串
int BF(const String *s, const String *sub, int pos);//串匹配
bool Replace(String *s, const String *t, const String *v, int pos);//用v替换从pos开始的t
bool ReplaceAll(String *s, const String *t, const String *v);//全部替换
bool Insert(String *s, int pos, const String *t);//在pos位置插入串t
bool DeletePos(String *s, int pos, int len);//删除pos位置后的len个字符
bool Delete(String *s, int pos, String *t);//删除串s中pos位置后的串t
void Show(const String *s); //打印串s
void Detroy(String *s); //销毁串s
#endif
2.串的操作
在String.c文件中给出串操作的代码实现:
#include <stdio.h>
#include "String.h"
#include <string.h>
int main(void)
{
String str;
StrAssign(&str, "hellowlor");
Show(&str);
String str1;
StrAssign(&str1, "lo");
//Delete(&str, 0, &str1);
//Show(&str);
String str2;
StrAssign(&str2, "lo");
ReplaceAll(&str, &str1, &str2);
Show(&str);
//String str1;
//StrAssign(&str1, "wo");
//Show(&str1);
//int pos = BF(&str, &str1, 0);
//printf("%d\n", pos);
//Insert(&str, 3, &str1);
//Show(&str);
//DeletePos(&str, 8, 3);
//Show(&str);
return 0;
}
//串赋值,将常量串chars赋给s
void StrAssign(String *s, const char *chars)
{
if (NULL == s || chars == NULL)
{
return;
}
int len = strlen(chars);
if (len > SIZE)
{
return;
}
for (int i = 0; i < len; ++i)
{
s->elem[i] = chars[i];
}
s->length = len;
}
//串拷贝,将串src中的内容拷贝到dest中
void StrCpy(String *dest, const String *src)
{
if (NULL == dest || NULL == src)
{
return;
}
int len = GetLength(src);
for (int i = 0; i < len; ++i)
{
dest->elem[i] = src->elem[i];
}
dest->length = len;
}
//判断串是否为空
bool IsEmpty(const String *s)
{
return s->length == 0;
}
//清空串,因为这里是顺序存储,所以直接将有效串长置为0即可
void Clear(String *s)
{
s->length = 0;
}
//获取有效串长
int GetLength(const String *s)
{
return s->length;
}
//从主串s的pos位置后去len个字符组成子串并赋值给sub
bool SubString(String *sub, const String *s, int pos, int len)
{
if (pos < 0 || len < 0 || (pos + len > SIZE))
{
return false;
}
for (int i = 0; i < len; ++i)
{
sub->elem[i] = s->elem[pos + i];
}
sub->length = len;
return true;
}
//男朋友匹配算法,从pos位置开始在s中查找第一个sub串的位置
int BF(const String *s, const String *sub, int pos)
{
if (NULL == s || NULL == sub || pos < 0 || pos >= s->length)
{
return -1;
}
int i, j;
for (i = pos; i < s->length; ++i) //i指向主串中匹配的起始位置
{
for (j = 0; j < sub->length; ++j)
{
if (s->elem[i + j] != sub->elem[j])
{
break;
}
}
//说明上面的for循环执行完以后已经在主串中找到完全匹配的子串
if (j == sub->length)
{
return i;
}
}
return -1;
}
//用v替换主串s中从pos位置开始的串t
bool Replace(String *s, const String *t, const String *v, int pos)
{
int iPos = BF(s, t, pos); //先在s中找到待替换子串的位置
if (iPos == -1)
{
return false;
}
//先删t,再插入v
Delete(s, iPos, (String*)t);
Insert(s, iPos, v);
return true;
}
//用v替换主串s中的所有子串t
bool ReplaceAll(String *s, const String *t, const String *v)
{
int iPos = BF(s, t, 0);
if (iPos == -1)
{
return false;
}
while (iPos != -1)
{
Delete(s, iPos, (String*)t);
Insert(s, iPos, v);
//这里之所以要加上v->length,就是防止v和t相等的情况下造成的死循环
iPos = BF(s, t, iPos + v->length);
}
//先删t,再插入v
return true;
}
//在主串s中的pos位置插入子串t
bool Insert(String *s, int pos, const String *t)//在pos位置插入t
{
if (pos < 0 || pos >= SIZE)
{
return false;
}
//如果待插入的子串的串长和主串的串长加起来超过了最大长度,则依次挤出超出的字符
if (s->length + t->length > SIZE)//
{
for (int i = s->length - t->length + 1; i >= pos; --i)
{
s->elem[i + t->length] = s->elem[i];
}
}
else
{
for (int i = s->length - 1; i >= pos; --i) //向后挪t->length个位置
{
s->elem[i + t->length] = s->elem[i];
}
}
for (int i = 0; i < t->length; ++i)
{
s->elem[pos + i] = t->elem[i];
}
//更新插入子串后的主串串长
s->length = s->length + t->length > SIZE ? SIZE : s->length + t->length;
return true;
}
//删除主串s中从pos位置开始的len个字符
bool DeletePos(String *s, int pos, int len)
{
if (pos < 0 || pos >= SIZE || pos + len > s->length)
{
return false;
}
for (int i = pos + len; i <= s->length; ++i)
{
s->elem[i - len] = s->elem[i];
}
s->length -= len;
return true;
}
//删除主串s中从pos位置后的子串t
bool Delete(String *s, int pos, String *t)
{
int index = BF(s, t, pos);
if (index < 0)
{
return false;
}
DeletePos(s, index, t->length);
return true;
}
//打印串s
void Show(const String *s)
{
for (int i = 0; i < s->length; ++i)
{
//注意这里只能单个字符打印,不能直接使用%s打印,因为串中没有结尾标志
printf("%c", s->elem[i]);
}
printf("\n");
}
void Detroy(String *s)
{
Clear(s);
}