161 阅读4分钟

串的定义

字符串String:是由零个或多个字符组成的有限序列。
一般记为S="a₁a₂a₃a₄a₅....":S是串名,引号括起来的字符序列是串的值,字符的个数为串的长度

  • 子串:串中任意个连续的字符组成的子序列
  • 主串:包含子串的串
  • 字符在主串中的位置:字符在串中的序号
  • 子串在主串中的位置:子串的第一个字符在主串中的位置
  1. 串是一种特殊的线性表,数据元素之间呈线性关系
  2. 串的数据对象限定为字符集
  3. 串的基本操作,如增删改查等通常以子串为操作对象

串的基本操作

//假设有串T = "",S = "iPhone 11 Pro Max?",W = "Pro"

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.
//【字符集编码】:每个字符在计算机中对应一个二进制数,比较字符的大小其实就是比较二进制数的大小

串的存储结构

顺序存储

结构体

#define MAXLEN 255
//静态数组
typedef struct{
    char ch[MAXLEN];   //每个分量存储一个字符
    int length;        //串的实际长度
}SString;

//动态数组
typedef struct{
    char *ch;     //按串长分配存储区,ch指向串的基地址
    int length;   //串的长度
}HString;
/*
HString S;
S.ch = (char *)malloc(MAXLEN * sizeof(char));
S.length = 0;
*/
/*
    方案一:专门变量记录length
    方案二:ch[0]充当Length,字符的位序和数组下标相同
    方案三:没有Length变量,以字符'\0'表示结尾(对应ASCII码的0)
    方案四:舍弃ch[0],设置Length变量
*/

求子串

bool SubString(SString &Sub,SString S,int pos,int len){
    //子串范围越界
    if(pos + len - 1 >S.length)
        return false;
    for(int i = pos;i < pos + len;i++)
        Sub.ch[i - pos + 1] = S.ch[i];
    Sub.length = len;
    return true;
}

比较

int StrCompare(SString S,SString T){
    for(int i=1;i<S.length && i<=T.length;i++){
        if(S.ch[i] != T.ch[i])
            return S.ch[i] - T.ch[i];
    }
    //扫描过的所有字符都相等,则长度大的串更大
    return S.length - T.length;
}

定位

int Index(SString S,SString T){
    int i = 1,n = StrLength(S),m = StrLength(T);
    SString sub;      //用于暂存子串
    while(i <= n-m+1){
        SubString(sub,S,i,m);
        if(StrCompare(sub,T) != 0)
            i++
        else
            return i;  //返回子串在主串中的位置
    }
    return 0;          //S中不存在与T相等的子串
}

链式存储

结构体

typedef struct StringNode{
    char ch;                   //存储密度低
    struct StringNode *next;
}StringNode,*String;

typedef struct StringNode{
    char ch[5];
    struct StringNode *next;
}StringNode,*String;

字符串的模式匹配

在主串中找到与模式串相同的子串,并返回其所在位置

朴素模式匹配算法

将主串中所有长度位m的子串依次与模式串对比,直到找到一个完全匹配的子串,或所有的子串都不匹配为止

//Index(S,T):通过基本操作实现

//不使用字符串的基本操作,直接通过数组下标实现朴素模式匹配算法
//若当前子串匹配失败,则主串指针i指向下一个子串的第一个位置,模式串指针j回到模式串的第一个位置
//若j>T.length,则当前子串匹配成功,返回当前子串的第一个字符的位置  i-T.length

int Index(SString S,SString T){
    int i = 1;
    int j = 1;
    while(i <= S.length && j <= T.length){
        if(S.ch[i] == T.ch[i]){
            ++i;
            ++j;    //继续比较后续字符
        }
        else{
            i = i - j + 2;
            j = 1;  //指针后退重新开始匹配
        }
    }
    if(j > T.length)
        return i - T.length;
    else
        return 0;
}

/*
    最坏时间复杂度 = O(nm)
    每个子串都要对比m个字符,共n-m+1个子串,复杂度 = O((n-m+1)m) = O(nm)
*/

KMP算法

每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的"部分匹配"的结果将模式向右"滑动"尽可能远的一段距离后,继续进行比较

//不匹配的字符之前,一定是和模式串一致的
int Index_KMP(SString S,SString T,int next[]){
    int i = 1;
    int j = 1;
    while(i <= S.length && j <= T.length){
        if(j == 0 || S.ch[i] == T.ch[j]){
            ++i;
            ++j;          //继续比较后继字符
        }
        //匹配失败时,主串指针i不回溯
        else
            j = next[j];  //模式串向右移动
    }
    if(j > T.length)
        return i-T.length;//匹配成功
    else
        return 0;
}

/*
    最坏时间复杂度:O(m+n)
    求next数组时间复杂度 O(m)
    模式匹配过程最坏时间复杂度O(n)
*/

void getNext(char t[],int next[]){
    next[0] = 0;
    for(int i = 1,j = 0;i < strlen(t);i++){
        while(j > 0 && t[i] != t[j]){
            j = next[j-1];
        }
        if(t[i] == t[j])
            j++;
        next[j] = j;
    }
}

//next[1] = 0;next[2] = 1;


//对next数组进行进一步的优化-->nextval数组
void getNextval(SString T,int next[],int nextval[]){
    nextval[1] = 0;
    for(int j = 2; j <= T.length;j++){
//判断原j对应的next[j]指向的串元素,是否与j对应的串元素相等,如相等则直接替换,不等则下一个
        if(T.ch[next[j]] == T.ch[j])
            nextval[j] = nextval[next[j]];
        else
            nextval[j] = next[j];
    }
}