什么是串呢?我们打字输入的信息,便可称为串。串其实比较简单,类似于的线性表。我们在各种编程语言中直接使用,比如

char [],或者 int []

一、基本概念

定义:由零个或多个字符组成的有限序列。串中字符的个数称为串的长度,含有零个元素的串叫空串

二、串的存储结构

1.定长顺序存储表示

typedef struct{
    char str[maxSize+1];
    int length;
}Str;

2.变长分配存储

typedef struct{

char *ch;

int length;

}Str;

三、基本操作

1.赋值操作

串的赋值操作必须对每个元素逐一进行赋值操作

使用格式strassign(str,"cur input");

int strassign(Str& str,char* ch){
    if(str.ch)
       str free(str.ch);//释放原串空间
    int len=0;
    char *c=ch;
    while(*c){
        ++len;
        ++c;
}
if(len==0){
    str.ch=NULL;
    str.length=0;
    return 1;
}
else
{
    str.ch=(char*)malloc(sizeof(char)*(len+1));//len+1因为多分配了“\0”
    if(str.ch==NULL)
        return 0;
    else{
        c=ch;
        for(int i=0;i<length++i,++c)
            str.ch[i]=*c;
        str.length=len;
        return 1;
}
}
}

2.取串长

直接用str.length

在使用变长分配存储表示时

int strlength(Str str){

   return str.length;

}

3.串比较操作

比较规则为,字符串A和B的待比较字符分别为a和b,(值大小根据ascll码)

若a>b,则A>B

若a<b,则A<B

若a=b,则按之前的规则继续往下比较下一对字符,一直比较,当某个串先结束则该串为较小的串。

两串同时结束,则两串相等。

int strcompare(Str str){
    for(int i=0;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
}

4.串连接操作

两个串首尾相接,合并成一个字符串的操作称为串连接操作。

5.求子串

下面状态实现了求str中从pos位置开始,长度为len的子串

int substr(Str& substr,Str str,int pos,int len){

        if(pos<0||pos>=str.length||len<0||len>str.length-pos)
            return 0;
        if(substr.ch){
            free(substr.ch);
            substr.ch=NULL;
}
if(len==0)
{

    substr.ch=NULL;
    substr.length=0;
    return 1;
}
else
{
    substr.ch=(char*)malloc(sizeof(char)*(len+1));
    int i=pos;
    int j=0;
    wwhile(i<pos+len){
        substr.ch[j]=str.ch[i];
        ++i; 
        ++j;
}
substr.ch[j]='\0';
substr.length=len;
return 1;
}
}

6.串清空

int  clearstr(Str& str){

       if(str.ch){

       free(str.ch);

       str.ch=NULL;

}

        str.length=0;

         return 1;

}

四、模式匹配算法

1.简单模式匹配算法

子串的定位操作称为串的模式匹配,待定位的子串称为模式串

基本思想:从主串的第一个字符开始比较,

若相等,则继续逐一比较后续字符。

否则,从主串的第二个字符开始,再次用上一步方法左比较,

以此类推,直到比较完模式串中的所有字符。

若匹配成功,则返回模式串在主串中的位置

若匹配失败,则返回一个可区别于主串所有位置的标记,如0

下图展示了主串“ABABCABCACBAB”和“ABCAC”的六次匹配过程,黄色区域表示这次中做过比较的字符,红色代表字符不等

int index(Str,Str substr){
    int i=1,j=1,k=i;
    while(i<=str.length && j<=substr.length){
        if(str.ch[i]==substr.ch[j])
    {
        ++i;
        ++j;
    }
    else{
        j=1;
        i=++k;
}
}
if(j>substr.length)
    return k;
else return 0;
}

2.KMP算法

回顾上面简单的匹配算法,会发现存某些多余的比较。

KMP算法利用比较过的信息,i指针不需要回溯,仅将子串向后滑动一个合适的位置,并从这个位置开始和主串进行比较。

这个合适的位置仅与子串本身的结构有关。

(1)先搞清楚几个小概念

  1. 前缀:除去最后一个字符外,字符串的所有部子串
  2. 后缀:除去第一个字符外,字符串的所有部子串
  3. 部分匹配值:为字符串的前缀和后缀的最长相等前后缀长度

举例:“ababa”

'a'的前缀和后缀都为空集,最长相等前后缀长度为0

’ab‘的前缀 为{a},后缀为{b},{a}\cap{b}=空,最长相等前后缀长度为0

aba的前缀为{a,ab},后缀为{a,ba},{a,ab}\cap{a,ba}={a},最长相等前后缀长度为1

abab,前缀{a,ab,aba,ba}\cap后缀{bab,ab,b}={ab},最长相等前后缀长度为2

ababa,前缀{a,ab,aba,abab}\cap后缀{a,ba,aba,baba}={a,aba},最长相等前后缀长度为3

故部分匹配值为 00123

(2)KMP实例

主串ababcabaacbab,子串为abcac

根据(1)中方法得出子串的部分匹配值为00010,将部分匹配值写为数组形式得到next数组

编号12345
Sabcac
next00010

使用next数组进行字符串匹配,

第一次匹配:a与c不匹配,前面两个字符’ab‘匹配,查表可知,最后一个匹配字符b对应的部分匹配值为0,

因此按照 公式     移动位数=已匹配的字符数-对应的部分匹配值

    有2-0=2,所以将子串后移2位, 进行第二次匹配

第二次匹配中,c与b不匹配,前面4个字符’abca‘是匹配的,最后一个匹配字符a对应的部分匹配值为1,

有4-1=3,将子串向后移动3位,如下进行第三次,

第三次匹配全部匹配成功

KMP时间复杂度(n+m)

(某乎的高赞解释:https://www.zhihu.com/question/21923021

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值