数据结构——串

介绍

字符串一般简称为串,串是一种特殊的线性表。

串的规定,第一个 字符下标为1。(可以看下图中i的取值)

两个串内容必须一模一样才称为相等。

存储结构

顺序存储(少用)

c 复制代码
//顺序存储(数组)
#define MAXLEN 255
typedef struct
{
    char ch[MAXLEN + 1];//末尾存放'\n'
    int length;//当前长度
}SString;
c 复制代码
//堆式存储(指针)
typedef struct
{
    char *ch;//若为非空串,则为串分配空间,否则ch为NULL
    int length;//当前长度
}

链式存储

c 复制代码
#define CHUNKSIZE 80//由用户自定义块大小
typedef struct Chunk
{
    char ch[CHUNKSIZE];
    struct Chunk* next;
}Chunk;
typedef struct
{
    Chunk *head, *tail;//串的头尾指针
    int length;//串的当前长度
}LString;

模式匹配算法

字串的定位运算称为串的模式匹配串匹配

BF算法

它是一种暴力算法,就是一个个字符比较,若匹配成功,则返回主串中子串第一个字符出现的位置;不成功返回0。

用的是顺序表示的串。

步骤

---> 分别用 i(初始化为pos) 和 j(初始化为1,串规定第一个字符下标为1) 来遍历 主串 和 子串 ;

---> 当主串和子串字符相同 i++ ,j++ ;

---> 当主串和子串字符不同, i = i - j + 2 (i从下一个i开始继续遍历,这个公式是找规律得出的) j = 1(子串回到开头);

---> 直到 j > T.length (子串遍历完了) 返回 i - T.length (i减掉字串长度,便是

主串中开始匹配的其实位置)

c 复制代码
int Index_BF(SString S, SString T, int pos)
{//S为主串,T为字串,pos为在主串开始查找的地址
    int i = pos;
    int j = 1;
    //整个暴力的遍历一遍
    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;//如果能找到,j一定会大于字串长度,则返回位置
    else return 0;
}

KMP算法

我们会发现BF算法每次匹配失败都得从头开始,非常浪费时间,KMP便在匹配失败后的 j 加以改变,让他的匹配次数大大缩短。

关于具体原理可以去B站搜索,讲得都很清楚。

c 复制代码
//KMP算法
int Index_KMP(SString S, SString T, int pos)
{
	int i = pos;
	int j = 1;
    while(i <= S.length && j <= T.length)
    {
        if(j == 0 || S.ch[i] == T.ch[i]) {++i; ++j;}
        else j = next[j];//只由子串决定,与主串无关
	}
}

整个运算过程 i 不会回溯,一直加到主串末尾或找到子串为止,而每轮i中子串哪个位与主串比较,由next数值决定;匹配next数组的值与主串无关,只与子串有关,计算过程大概如下

c 复制代码
//next的函数值
void get_next(int* next, SString T)
{
    int i = 1;
    int j = 0;
    next = new int [T.length + 1];
    next[1] = 0;
    while(i <= T.length)
    {
        if(j == 0 || T.ch[i] == T.ch[j]) next[++i] = ++j;//若发现i,j对应的字符相等,则说明第一个到i-1,i+1到j-1的个字符都相等,加上第i和j个字符,前缀后缀变为新的且相等,子串长度加一,就等于第j+1(算j+1z只看前j个字符)个字符的next数组值
        else j = next[j];//看门牌,如果上面的i,j不相等,就让j的next数组值对应的那个位置上的字符再与i比较,逻辑如上,不断重复,直到j再次等于0,说明前面没有如何子串相等,则next数组值等于1
	}
}

有些情况下,next数组会重复比较,对于此我们又进行了优化

c 复制代码
void get_nextval(SString T, int* nextval)
{
    int i = 1;
    int j = 0;
    next = new int [T.length + 1];
    next[1] = 0;
    while(i <= T.length)
    {
        if(j == 0 || T.ch[i] == T.ch[j])
        {
            ++i;++j;
            if(T.ch[i] != T.ch[j]) nextval[i] = j;//如果下一个不等于,则next修正值等于j值(这个等于啥的规律是找出来的,有兴趣可以去搜一搜)
            else nextval[i] = nextval[j];//如果下一个还等于那就next修正值都相等
		}
        else j = nextval[j];
    }
}
相关推荐
皓月斯语5 小时前
B3842 [GESP202306 三级] 春游 题解
数据结构·c++·算法·题解
春日见6 小时前
算法与数据结构----哈希表
数据结构·人工智能·算法·机器学习·自动驾驶·哈希算法·散列表
萌动的小火苗6 小时前
嵌入式开发中的栈与队列:任务调度为什么依赖数据结构
数据结构·c++·单片机·嵌入式硬件
叩码以求索6 小时前
统计按位或能得到最大值的子集数目(一)
数据结构·算法
tachibana27 小时前
hot100 数组中的第K个最大元素(215)
java·数据结构·算法·leetcode
星恒随风7 小时前
C++ STL 栈详解:stack 的使用、经典题目与简单模拟实现
开发语言·数据结构·c++·笔记·学习
txzrxz7 小时前
单调队列讲解
数据结构·c++·算法·单调队列
Keven_118 小时前
算法札记:树状数组的用途
数据结构·算法
cpp_25018 小时前
P1540 [NOIP 2010 提高组] 机器翻译
数据结构·c++·算法·队列·noip·洛谷题解
星恒随风11 小时前
C++ STL 详解:list 的使用、迭代器失效、模拟实现与 vector 对比
开发语言·数据结构·c++·笔记·学习·list