【数据结构】八、字符串的操作以及BF、KMP算法

目录

一、什么是串?

二、串的结构体定义

三、通过字符输入的方式创建一个串

四、字符串的拼接

五、字符串比较

六、字符串查找子字符串在主字符串中的下标✨

1)BF(暴风)算法

2)KMP算法


一、什么是串?

串是由零个或多个字符组成的有限序列。通常,串中的字符可以是字母、数字、标点符号等。串的长度是指串中字符的个数。例如,"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站结合视频进行学习。也可以看看下面这篇:

【数据结构】KMP算法(详解)-CSDN博客

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;
    }

}

最后感谢你观看完我的文章,如果文章对你有帮助,可以点赞收藏评论,这是对作者最好的鼓励!不胜感激🥰🥰

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值