数据结构系列-8 串

 

1.定义

串就是字符串,是0个或者多个字符组成的有序序列。

2.串的操作:

  1. 赋值操作
  2. 获取长度操作
  3. 串比较操作
  4. 串连接操作
  5. 求子串操作:求给定字符串,从某一位置开始,到某一位置结束的串的操作
  6. 串清空操作

 3.串的模式匹配算法       

  1. 幼稚字符匹配算法(优点容易理解,缺点效率低)
    1. 匹配串和原字符串对齐,
    2. 依次比较,是否所有字符串相同。
    3. 如果不相同,匹配串开始下班,和原字符串第二个对齐,比较指针指向匹配串开头(称为回溯)重新开始比较
    4. 如果再发现不同,匹配串移动到,原字符和第三位置对齐,比较指针回溯。重新比较,依次类推。
  2. KMP算法

(1)算法原理说明

        KMP和幼稚算法的大体步骤相同,但是比较到不同位置后,回溯和重新对齐的位置不同。     

  假如,我们有两个字符串,(原字符串:ABBABBABABAAABABAAAA,模式串:ABBABAABABAA)我们我们是比较了多个才发现不同,比如6个,如下。

第一次比较,我们再横线处发现不同。
    原字符串:ABBAB|BABABAAABABAAAA
    模式串  :ABBAB|AABABAA

  如果是幼稚模式我们会这样,模式串左移一位,比较指针,回溯到模式串开头。
        A|BBABBABABAAABABAAAA
         |ABBABAABABAA

  可是其实我们已经比较过5个字符串,这些比较过的字符,比较指针根本不用用回溯。模式串则可以移动3位     
    原字符串:ABBAB|BABABAAABABAAAA
    模式串  :   AB|BABAABABAA
  为什么是三位不是5位,我们看一下比较串中已经比较的5位(AB)B(AB),主意括号括起来的部分是一样的,其实我们只敢确定(AB)B是不同的,从原字符串中 ABB(AB)|BABABAAABABAAAA 和(AB)B(AB)中(AB)B后面部分又有可能是相同的了。这个匹配串中相同的部分,我们就叫公共前后缀。
    所以,KMP算法的核心就是:
        1.比较指针不回溯(比较变成O(n))
        2.模式串,从前缀移动到后缀位置。
            

2. next 数组

 还是上面这个例子(原字符串:ABBABBABABAAABABAAAA,模式串:ABBABAABABAA)
    原字符串:ABBAB|BABABAAABABAAAA
    模式串  :ABBAB|AABABAA

如果我们每次发现,不同,都取出匹配串前面的子串,再计算出,公共前后缀的大小,再回溯,其实也是很费时的。索性一旦确定子串,子串的公共前后缀就确定了。我们需要移动子串的位置就是,子串长度-公共子串大小。 我们可以利用匹配串提前算出这些信息并且存到一个数组里。逻辑对应关系如下。
注意:next数组的1位置代表 匹配串第一个字符不是0


模式串       :   A B B A B A A B A B  A  A
数组下标     : 0 1 2 3 4 5 6 7 8 9 10 11 12
匹配串移动数 : 0 0 1 1 1 2 3 2 2 3  2  3  2

next数据计算规则如下:
特殊情况1:1的位置,不匹配固定是 0,这时,比较指针,和匹配串一起向前移动一位
特殊情况2: 2的位置,1匹配,二不匹配,比较串移动一位。
特殊情况3:前两个位置匹配,第三位置匹配,也是固定移动一位
情况4    :A B B 没有前后缀,值为1
情况5    :A B B A 公共前后缀为A,值为2 (公共前后缀数加1)
情况6    :A B B A B 公共前后缀为AB,值为3(公共前后缀数加1)

注意前后缀的原则是:
前后缀是最大前后缀,但是不是子串本身。


//next 数组算法c语言实现

void getnext(char ch[],int length, int next[]){//length为串的长度
   
    next[1]=0;
    int i=1, j=0;
    while(i<length){ 
        if(j==0|| ch[i]== ch[j]){ //j是上一次确定可以移动的位置,i是已经比较过的位置
                                  //
            ++i;
            ++j;
            next[i] = j;
        } else {
            j=next[j];
        }

    }
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值