05 串 | 数据结构与算法

1. 串

1. 串的定义

  1. 串:零个或多个 字符 组成的 有限 序列
  2. 串的长度:串中字符的个数
  3. 空串:长度为 0 的串 ""
  4. 非空串:String = "c1c2c3...cn"
    1. 串名:String
    2. 定界符:" "
    3. 数据元素:字符 ci
  5. 主串:包含子串的串
  6. 子串:串中任意个 连续 的字符组成的子序列
  7. 子串的位置:子串中的第一个字符在主串中的序号
  8. 串相同:串长度相同并且各个对应的字符也相同

2. 串的存储设计

  1. 顺序串:采用连续设计存储的字符序列
    1. 存储形式

      1. 非压缩形式image

      2. 压缩形式 image

    2. 如何表示串的长度

      1. 用一个变量记录实际长度
      2. 在串尾增加一个不会在串中出现的特殊字符作为终止符,例如 '\0'
  2. 链接串:采用链接存储设计来存储串。串的链式存储结构和线性表的串的链式存储结构类似,采用单链表来存储串,结点的构成是:
    1. data域:存放字符,data域可存放的字符个数称为结点的大小;
    2. next域:存放指向下一结点的指针。
      若每个结点仅存放一个字符,则结点的指针域就非常多,造成系统空间浪费,为节省存储空间,考虑串结构的特殊性,使每个结点存放若干个字符,这种结构称为块链结构。

2. 串的模式匹配 / \(KMP\) 算法

1. 串的匹配

  1. 目标串:主串
  2. 模式串:子串
  3. 匹配:在目标串当中找到子串的位置

2. \(KMP\) 算法

  1. 算法出发点:利用前面已经匹配的结果,进行 无回溯 的匹配

  2. next[] 表示将模式串向右滑动尽可能远的一段距离

  3. next[]的本质:找到模式串中 最长的相同前缀和后缀

  4. 算法:

    1. 计算 next[] 数组
    /*
     * next的定义
     * next[j] = -1, when j = 0;
     * next[j] = max{相同的前缀与后缀的长度}
     * next[j] = 0, otherwise(即没有匹配到)
     */
    
    void build_next(vector<int>& next, string str){
       next[0] = -1;
       int i = 0 , j = -1; 	//j = -1,i and j both ++;
       while(i < str.length() - 1){
           if(j == -1 || str[i] == str[j]) {
               next[++i] = ++j;
           }
           else j = next[j]; 	//can not match, j goes back
       }
    }
    
    1. 匹配
    int strStr(string target_string, string pattern_string) {
        int n = target_string.length();
        int m = pattern_string.length();
        int i = 0 , j = 0;
        vector<int> next(m);
        build_next(next , pattern_string);  //get next[]
        while(i < n && j < m){
            if(j == -1 || target_string[i] == pattern_string[j]){
                ++i ,++j;
            }
            else j = next[j];
        }
        if(j == m) return i - j;    //j == m, 匹配成功
        else return -1;     // fail to match
    }
    
  5. 改进的 \(KMP\) 算法

    1. 对于下面这种情况:有多个相同的连续字符,显然如果匹配不成功可以直接跳过这一大段连续的相同字符,因此对于新的 nextval[],我们有
      1. 如果当前模式串位置的字符和目标串位置的字符 不相同,那么 nextval[index] = next[index]
      2. 如果当前模式串位置的字符和目标串位置的字符 相同,那么 nextval[index] = nextval[next[index]]
    2. 例子
    index 0 1 2 3 4 5 6 7 8 9 10 11 12
    pattern a a a b b a b c c a a a a
    next -1 0 1 2 0 0 1 0 0 0 1 2 3
    nextval -1 -1 -1 2 0 -1 1 0 0 -1 -1 -1 3
    1. 算法
    void build_nextval(vector<int>& nextval, string str){
        nextval[0] = -1;
        int i = 0 , j = -1;
        while(i < str.length() - 1){
            if(j == -1 || str[i] == str[j]) {
                ++i , ++j;
                /*nextval[index] = next[index]*/
                if(str[i] != str[j]) nextval[i] = j;
                /*nextval[index] = nextval[next[index]]*/
                else nextval[i] = nextval[j];
            }
            else j = nextval[j];
        }
    }
    
posted @ 2022-10-17 19:40  RadiumStar  阅读(82)  评论(0编辑  收藏  举报