数据结构-串 & KMP

字符串的简称, 字符串本身就是一种数据结构, 由零个或者多个字符组成的有限序列(顺序存储结构)

串的定义及子串

  1. 定义 :在C语言中, 串可以用字符数组来定义:

    char str[] = "adrui";

    这里str 是串的名字, 串长为5 ,而str数组存储的字符分别为'a','d', 'r', 'u', 'i''\0'

    其中'\0'是编译器识别串结束的标志, 说以str串长为5, str数组长度为6

  2. 子串: 串中任意连续字符组成的序列称为该串的子串, 包含子串的串称为主串, 主串的某一子串在主串中的位置为该子串第一个字符在主串中的位置(保证从这个位置开始能和子串匹配)

空白字符

\n, '\r', '\t', ' ' 等空白字符也可以作为串的元素

特点

  • 可以看成是限定了元素类型为字符的线性表
  • 操作集上主要针对串内的一个子串

C语言字符数组和字符型指针

  • 字符数组

    char str[] = "adrui";  /**静态分配, 在内存中开辟一块区域, 存储'a', 'd', 'r', 'u', 'i'和'\0'
                        串长为5,数组长为6**/
    char s[100];           //静态分配, 在内存中开辟一区域, 数组长度为100, 串长不定(自己可赋值要                              以'\0'结尾)

    字符数组开辟后, 地址和长度均不可变, 不加const修饰符时可修改某一位置的元素, 加const之后不可修改

  • 字符指针

    char * str1 = "adrui";//str1指向内存中某一块区域,该区域存着该字符串常量(不可修改)
    char str[] = "adrui";
    str1 = str; //可修改(str本身可修改)
    const char * str2;//指向的区域元素不可修改, 但是本身可修改指向
    char * const str3;//本身指向不可修改, 指向区域的元素可以修改

    注: 修饰符定义可修改, 还要看指向的指针或者数组是否支持元素修改

    const char *且不能赋给char *, "adrui" 这种字符串常量本身也是不可改的

串定义

  1. 定长顺序存储表示及操作集:

    typedef struct{
       char ch[MAX_SIZE + 1];//最大容量为MAX_SIZE, 多出来的1用来存'\0'
       int len;          //串长
    }Str;
    
    int strLength(const char *p){        //获取串长
       int len = 0;
       while(*p){                      //串尾为'\0', 其整数值为0, 到达串尾会退出循环
           ++p;
           ++len;
       }
       return len;
    }
    
    void strAssign(Str &str, const char *p){ //赋值
       int length = strLength(p);
       for(int i = 0; i <= length; ++i)         //赋值[0, len],p[len]为'\0'
           str.ch[i] = p[i];
       str.len = length;
    }
    
    int StrLength(Str str){
       return str.len;
    }
  2. 变长分配存储表示及操作集:

    typedef struct{
       char *ch;
       int len;
    }Str;
    
    int strLength(const char *p){       //获取串长
       int len = 0;
       while(*p){
           ++p;
           ++len;
       }
       return len;
    }
    
    void strAssign(Str &str, const char *p){    //赋值
       int length = strLength(p);
       if(length == 0) {                       //空串
           free(str.ch);
           str.ch == NULL;
       }
       else {
           str.ch = (char *)malloc((length + 1) * sizeof(char)); //开辟空间
           for(int i = 0; i <= length; ++i)         //赋值[0, len],p[len]为'\0'
            str.ch[i] = p[i];
        }
       str.len = length;
    }
    
    int StrLength(Str str){
        return str.len;
    }
    
    int strCompare(Str s1, Str s2){                 //按字典序比较
       for(int i = 0; i < s1.len && i < s2.len; ++i)
           if(s1.ch[i] != s2.ch[i])
               return s1.ch[i] - s2.ch[i];
       return s1.len - s2.len;
    }
    
    int index(Str str, Str substr){
        int len1 = StrLength(str);
        int len2 = StrLength(substr);
        for(int i = 0; i <= len1 - len2; ++i){
            int j, k = i;
            for(j = 0; j < len2 && str.ch[k] == substr.ch[j]; ++k, ++j);
            if(j == len2) return i;
        }
        return -1;
    }
    
    void strPrint(Str str){
       if(str.len == 0) {
           printf("\n");
           return;
       }
       printf("%s\n", str.ch);
    }

串的模式匹配算法

串的模式匹配: 对一个串中某子串的定位, 其中待定位的子串称为模式串

  • 暴力枚举

    int index(Str str, Str substr){
      int len1 = StrLength(str);
      int len2 = StrLength(substr);
      for(int i = 0; i <= len1 - len2; ++i){
          int j, k = i;
          for(j = 0; j < len2 && str.ch[k] == substr.ch[j]; ++k, ++j);
          if(j == len2) return i;
      }
      return -1;
    }
  • KMP匹配算法

    有关Kmp算法的原理这里就不讲了, 转载一篇博文

    KMP详解

    int nxt[MAX_SIZE + 1];//index from 1
    void getNext(Str substr){                         
      nxt[1] = 0;
      int i = 1, j = 0;
      while(i <= StrLength(substr)){
          if(j == 0 || substr.ch[i] == substr.ch[j]){
              ++i;
              ++j;
              nxt[i] = j;
          }else j = nxt[j];
      }
    }
    
    int kmp(Str str, Str substr){
      int i = 1, j = 1;
      while(i <= StrLength(str) && j <= StrLength(substr)){
          if(j == 0 || str.ch[i] == substr.ch[j]){
              ++i;
              ++j;
          }else j = nxt[j];
      }
      if(j > StrLength(substr)) return i - StrLength(str);
      return -1;
    }
  • 改进KMP算法:

    int nxt[MAX_SIZE + 1];//index from 1
    void getNext(Str substr){
       nxt[1] = 0;
       int i = 1, j = 0;
       while(i <= StrLength(substr)){
           if(j == 0 || substr.ch[i] == substr.ch[j]){
               ++i;
               ++j;
               nxt[i] = substr.ch[i] == substr.ch[j] ? nxt[j] : j;      //优化, 失配指针的移动
           }else j = nxt[j];
       }
    }
    
    int kmp(Str str, Str substr){
       int i = 1, j = 1;
       while(i <= StrLength(str) && j <= StrLength(substr)){
           if(j == 0 || str.ch[i] == substr.ch[j]){
               ++i;
               ++j;
           }else j = nxt[j];
       }
       if(j > StrLength(substr)) return i - StrLength(str);
       return -1;
    }

AC自动机

多个主串的模式串匹配算法, 以KMP算法和字典树为基础(有兴趣可以学习一下)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值