目录
一、什么是串?
串是由零个或多个字符组成的有限序列。通常,串中的字符可以是字母、数字、标点符号等。串的长度是指串中字符的个数。例如,"hello"、"123"、"abc"等都是串。串的研究对于文本处理、模式匹配、数据压缩等领域具有重要意义。本文主要使用动态数组存储串,并介绍串的基本操作以及代码实现。
二、串的结构体定义
typedef struct {
char* string; //字符串
int Capacity; //容量
int length; //字符数
}String;
三、通过字符输入的方式创建一个串
//初始化字符串
static void String_Init(String* str)
{
str->Capacity = 4;
str->string = NULL;
str->length = 0;
}
//判断是否需要增容
static void String_Full(String* str)
{
if (str->length == str->Capacity)
{
str->string = (char*)realloc(str->string, 2 * str->Capacity * sizeof(char));
str->Capacity *= 2;
}
}
//建立字符串
void String_Creat(String* str)
{
String_Init(str);
str->string = (char*)malloc(str->Capacity * sizeof(char));
char c;
int i = 0;
while (1)
{
c = getchar();
String_Full(str);
if (c == '\n')
break;
else
{
str->string[i++] = c;
str->length++;
}
}
str->string[i] = '\0'; //字符串尾标志
}
在每次添加字符时,先判断串是否达到最大容量,如果达到最大容量则对其进行增容操作,这里增容使用
realloc
函数,它可以重新申请一块更大的内存
四、字符串的拼接
//将字符串 2 的前 n 个字符插入到字符串 1 的尾部
void String_Cat(String* str1, String* str2, int n)
{
if (n > str2->length) n = str2->length;
for (int i = 0; i < n; i++)
{
String_Full(str1);
str1->string[(str1->length)++] = str2->string[i];
}
str1->string[str1->length] = '\0';
}
五、字符串比较
//字符串比较
int String_Compare(String str1, String str2)
{
int i;
for (i = 0; str1.string[i]!='\0' && str2.string[i] != '\0'; i++)
{
if (str1.string[i] > str2.string[i])
{
return 1;
}
else if (str1.string[i] < str2.string[i])
{
return -1;
}
}
if (str1.string[i] == '\0' && str2.string[i] == '\0')
return 0;
else if (str1.string[i] != '\0' && str2.string[i] == '\0')
return 1;
else
return -1;
}
六、字符串查找子字符串在主字符串中的下标✨
1)BF(暴风)算法
特点:简单、暴力
算法步骤:逐字符比较,若字符不匹配,则子字符串指针回到子字符串第一个位置,主字符串指针回到上次的第一个位置的下一个位置
如上图字符串,在第三个位置不相同,则将子串的abc移到主串的bab下方继续逐字符比较,发现第一个就不匹配,则子串abc移到主串abc的下方,比较成功,返回主串中的第二个a的下标2
//暴风算法
int String_BF(String parent, String child)
{
int i = 0; //i用于主串parent中的起始位置
int j = 0; //子串的起始位置
while (i < parent.length && j < child.length)
{
if (parent.string[i] == child.string[j])
{
i++;
j++;
}
else
{
i = i - j + 1; //i回溯到上一次匹配的首位的下一位
j = 0; //j回溯到子串的第一个位置
}
}
//当j大于子串长度,则说明匹配成功,返回主串中第一个相同元素的下标
if (j >= child.length)
{
return i - child.length;
}
return 0;
}
2)KMP算法
特点:高效、难
这个算法比较难懂,建议去b站结合视频进行学习。也可以看看下面这篇:
static int* finenext(char* ch)
{
/*计算next数组*/
int next[100] = { 0 };
int prefin_len = 0; //当前共同前后缀的长度
int i = 1; //字串指针和next指针
/*第一个位置不可能是重复的,所以一定为0,于是从1开始*/
while (i < strlen(ch))
{
//a b a b c
//0 0 1 2 0
if (ch[prefin_len] == ch[i])
{
prefin_len++;
next[i] = prefin_len;
i++;
}
else
{
if (prefin_len == 0)
{
next[i] = 0;
i++;
}
else
{
prefin_len = next[prefin_len - 1];
}
}
}
return next;
}
//字符串查找
int String_KMP(String str1, String str2)
{
int* next = finenext(str2.string);
int i = 0, j = 0;
while (i < str1.length)
{
if (str1.string[i] == str2.string[j])
{
i++;
j++;
}
else if (j > 0) //字符失配,根据next跳过字串前面一些字符
{
j = next[j - 1];
}
else //字串第一个匹配失败
i++;
if (j == str2.length)
return i - j;
}
}
最后感谢你观看完我的文章,如果文章对你有帮助,可以点赞收藏评论,这是对作者最好的鼓励!不胜感激🥰🥰