数据结构笔记——串

好好学习,天天向上

本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star

⭐⭐⭐⭐⭐转载请注明出处:https://blog.csdn.net/weixin_43461520/article/details/123946531

4.1 串的定义和基本操作

串(string)是由零个或多个字符组成的有限序列。

  • 基本操作

    • StrAssign(&T,chars):赋值操作。把串T赋值为chars。

    • StrCopy(&T,S):复制操作。由串S复制得到串T。

    • StrEmpty(S):判空操作。若S为空串,则返回TRUE,否则返回FALSE。

    • StrLength(S):求串长。返回串S的元素个数。

    • ClearString(&S):清空操作。将S清为空串。

    • DestroyString(&S):销毁串。将串S销毁(回收存储空间)。

    • Concat(&T,S1,S2):串联接。用T返回由S1和S2联接而成的新串

    • SubString(&Sub,S,pos,len):求子串。用Sub返回串S的第pos个字符起长度为len的子串。

    • Index(S,T):定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的

    • 位置;否则函数值为0。

    • StrCompare(S,T):比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0。

#include <iostream>

using namespace std;

#define MaxLen 255
typedef struct {
    char ch[MaxLen];    //为了便于计算ch[0]闲置,从ch[1]开始存放数据
    int length;
} SString;

//求子串。用Sub返回串S的第pos个字符起长度为len的子串
bool SubString(SString &Sub, SString S, int pos, int len) {
    if (pos + len - 1 > S.length) {
        return false;   //越界
    }
    for (int i = 0; i < len; i++) {
        Sub.ch[i + 1] = S.ch[pos + i];
    }
    Sub.length = len;
    return true;
}

//比较操作。若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
//按位比较
int StrCompare(SString s1, SString s2) {
    for (int i = 1; i <= s1.length && i <= s2.length; i++) {
        if (s1.ch[i] != s2.ch[i]) {
            return s1.ch[i] - s2.ch[i];
        }
    }
    return s1.length - s2.length;
}

//定位操作。若主串s中存在与串t值相同的子串,则返回它在主串s中第一次出现的位置;否则函数值为0
int Index(SString s, SString t) {
    int i = 1;
    int sLength = s.length; //主串的长度
    int tLength = t.length; //子串的长度
    SString sub;    //临时子串
    while (i <= sLength - tLength + 1) {
        SubString(sub, s, i, tLength);  //从i开始截取临时子串
        if (StrCompare(sub, t) == 0) {      //判断临时子串与子串是否相等
            return i;
        } else {
            i++;
        }
    }
    return 0;   //不存在这样的子串
}

4.2 串的存储结构

4.2.1 顺序存储

4.2.2 链式存储

4.3 字符串模式匹配

4.3.1 朴素模式匹配算法

该算法采用的是暴力匹配,依次从主串中挑出子串与模式串进行比较。

#include <iostream>

using namespace std;

#define MaxLen 255
typedef struct {
    char ch[MaxLen];    //为了便于计算使ch[0]闲置,从ch[1]开始存放数据
    int length;
} SString;

//若主串s中存在与模式串串t值相同的子串,则返回它在主串s中第一次出现的位置;否则返回0
//s:主串,t:模式串
int Index(SString s, SString t) {
    int i = 1;      //遍历判断时指向s
    int j = 1;      //遍历判断时指向t

    while (i <= s.length && j <= t.length) {
        if (s.ch[i] == t.ch[j]) { //如果当前正在比较的字符相等就比较下一个字符
            i++;
            j++;
        } else {
            i = i - j + 2;   //字符不相等时窗口向右滑动一格重新与模式串比较
            j = 1;
        }
    }
    if (j > t.length) {
        return i - t.length;
    }
    return 0;   //不存在这样的子串
}

从主串s中依次划出与子串 t 中大小相等的串,判断窗口与子串是否相等,不相等时窗口向右移动一格再判断,直到找出相应的子串或找不出对应的串为止。

跳出循环后,如果tIndex的值大于t的长度,说明t中的每个字符都比较完了,则表示已经找到了对应的子串,返回子串的起始下标。反之说明是由于主串中已经没有可比较的子串而跳出的循环,返回0表示找不到对应的子串。

4.3.2 KMP算法

在朴素模式匹配算法中,每次子串与模式串比较失败后,指针都回溯到新的子串起始处与模式串起始位置重新开始依次比较。但是通过前一次的比较,子串与模式串中的内容我们是知道的,所以不需要每次都从头开始重新比较。根据规律可以分析出当模式串的第几个字符匹配失败后下一次应该从第几个字符开始比较

定义一个 Next数组,用来记录当模式串的第几个字符匹配失败后,下一个应该从模式串的第几个字符开始继续往后匹配。每次匹配失败后通过查询Next数组就可以知道下次应该从第几个字符开始重新匹配,而不需要每次都从第一个字符进行比较,这就是KMP算法与朴素模式匹配算法的不同之处。

求Next数组

KMP算法代码实现

#include <iostream>
using namespace std;
#define MaxLen 255

typedef struct {
    char ch[MaxLen];    //为了便于计算使ch[0]闲置,从ch[1]开始存放数据
    int length;
} SString;

//获取next数组
void getNextArray(SString t, int next[]) {
    int i = 1;
    int j = 0;
    next[1] = 0;
    while (i <= t.length) {
        if (j == 0 || t.ch[i] == t.ch[j]) {
            // 若ti=tj,则 next[j+1] = next[j] + 1
            // 通俗的说,设此时i=4,t=1,这段代码的意思就是如果第4个字符能和第1个字符匹配上,
            // 那么在进行模式匹配时第5个字符匹配不上时下次就从第2个字符开始匹配,next[5]=2
            // 结合上图进行理解
            i++;
            j++;
            next[i] = j;
        } else {
            j = next[j];
        }
    }
}

//若主串s中存在与模式串串t值相同的子串,则返回它在主串s中第一次出现的位置;否则返回0
//s:主串,t:模式串
int Index_KMP(SString s, SString t, int next[]) {
    int i = 1;      //遍历判断时指向s
    int j = 1;      //遍历判断时指向t

    while (i <= s.length && j <= t.length) {
        if (j == 0 || s.ch[i] == t.ch[j]) { //如果当前正在比较的字符相等就比较下一个字符
            i++;
            j++;
        } else {
            j = next[j];
        }
    }
    if (j > t.length) {
        return i - t.length;
    }
    return 0;   //不存在这样的子串
}

⭐⭐⭐⭐⭐转载请注明出处:https://blog.csdn.net/weixin_43461520/article/details/123946531

本文已收录至我的Github仓库DayDayUPgithub.com/RobodLee/DayDayUP,欢迎Star

如果您觉得文章还不错,请给我来个点赞收藏关注

学习更多编程知识,WeChat扫描下方二维码关注公众号『 R o b o d 』:

posted @ 2022-04-03 23:01  Robod丶  阅读(51)  评论(0编辑  收藏  举报