数据结构编程笔记十一:第四章 串 定长顺序串以及模式匹配算法(BF和KMP)的实现

前几次我们介绍了栈和队列两种特殊的线性表,它们都是操作位置受限的线性表:限制了插入和删除操作发生的位置。

这次我们介绍另一种特殊的线性表,它虽然没有操作位置限制,但却有元素类型限制:它限制元素类型只能是字符,这样的线性表我们称之为串。

还是老规矩:

程序在码云上可以下载。
地址:https://git.oschina.net/601345138/DataStructureCLanguage.git

串可以进行很多操作,有很多有特色的操作是线性表中没有的,比如:串的模式匹配。

模式匹配算法分为BF和KMP算法两种,本次程序将基于实现的顺序串继续实现这两种模式匹配算法。

首先看看串的ADT定义:

ADT String {
       数据对象:D ={ai | ai∈Characterset,(i=1,2,…,n, n≥0)}
       数据关系:R1 = {<ai-1,ai>|ai-1,ai ∈ D,(i=2,3,…,n)}   
       基本操作:
        StrAssign (&T, chars)
        初始条件:chars 是字符串常量。
        操作结果:把 chars 赋为T的值。
        StrCopy (&T, S)
        初始条件:串 S 存在。
        操作结果:由串 S 复制得串T。
        DestroyString (&S)
        初始条件:串 S 存在。
        操作结果:串 S 被销毁。
        StrEmpty (S)
        初始条件:串 S 存在。
        操作结果:若 S 为空串,则返回true,否则返回 false。
        StrCompare (S, T)
        初始条件:串 S和T存在。
        操作结果:若S > T,则返回值> 0;若S = T,则返回值= 0;若S < T,则返回值< 0。
        StrLength (S)
        初始条件:串 S 存在。
        操作结果:返回 S 的元素个数,称为串的长度。
        Concat (&T, S1, S2)
        初始条件:串 S 1和S2存在。
        操作结果:用T返回由S1和S2联接而成的新串。
        SubString (&Sub, S, pos, len)
        初始条件:串 S 存在,1≤pos≤StrLength(S) 且  0≤len≤StrLength(S)-pos+1。
        操作结果:用Sub返回串S的第 pos 个字符起长度为len的子串。
        Index (S, T, pos)
        初始条件:串S和T存在,T是非空串,1≤pos≤StrLength(S)。
        操作结果:若主串 S 中存在和串 T 值相同的子串, 则返回它在主串 S 中第pos个字符之后第一次出现的位置;否则函数值为0。
        Replace (&S, T, V)
        初始条件:串S, T和 V 均已存在,且 T 是非空串。
        操作结果:用V替换主串S中出现的所有与(模式串)T相等的不重叠的子串。
        StrInsert (&S, pos, T)
        初始条件:串S和T存在,1≤pos≤StrLength(S)+1。
        操作结果:在串S的第pos个字符之前插入串T。
        StrDelete (&S, pos, len)
        初始条件:串S存在1≤pos≤StrLength(S)-len+1。
        操作结果:从串S中删除第pos个字符起长度为len的子串。 
        ClearString (&S)
        初始条件:串S存在。
        操作结果:将S清为空串。            
} ADT String 

在了解了串可以进行哪些基本操作之后,一起来看看这些操作的实现以及两种模式匹配算法的实现:

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>引入头文件<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

#include <stdio.h>   //使用了标准库函数 printf(),scanf()
#include <stdlib.h>  //使用了动态内存分配函数 malloc(),free()
#include <string.h>  //使用了字符串处理函数strlen() 

//>>>>>>>>>>>>>>>>>>>>>>>>>>>自定义符号常量<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 

#define OVERFLOW -2         //内存溢出错误常量
#define OK 1                //表示操作正确的常量 
#define ERROR 0             //表示操作错误的常量
#define TRUE 1              //表示逻辑正确的常量 
#define FALSE 0             //表示逻辑错误的常量
#define MAXSTRLEN 255       //最大串长
#define DestoryString ClearString  //DestoryString()和ClearString()作用相同 

//>>>>>>>>>>>>>>>>>>>>>>>>>>>自定义数据类型<<<<<<<<<<<<<<<<<<<<<<<<<<<<

typedef int Status;       //状态参量
typedef char ElemType;    //元素类型 

// 串的定长顺序存储C语言表示 
typedef unsigned char SString[MAXSTRLEN + 1]; // 0号单元存放串的长度,1号单元开始存储串值字符序列 

//--------------------------串的主要操作------------------------------

/*
    函数:Print
    参数:ElemType e 待访问元素 
    返回值:无 
    作用:访问元素,也就是打印输出 
*/
void Print(ElemType e){

    //指定遍历方式为控制台输出 
    printf("%c",e); 
}//Print 

/*
    函数:StrTraverse
    参数:SString T 待访问元素
          void(* Visit)(ElemType) 函数指针,可以指向一个函数 
    返回值:无 
    作用:(串遍历)打印输出串的内容 
*/
void StrTraverse(SString T, void(* Visit)(ElemType)){ 

    //依次遍历每个元素 
    for(int i = 1; i <= T[0]; i++) { 
        Visit(T[i]);
    }//for

    //输出换行,使结果美观 
    printf("\n");
}//StrTraverse

/*
    函数:StrAssign
    参数:SString T 定长串,采用我们自定义的数据类型,0号单元存放串长,
                    字符数据从1号单元开始存储。 
          chars 指向存储字符类型数据的指针,即指向一个已经存在的字符串, 
                这个串采用C语言默认的方式,数据从0号单元开始存储,以'\0'作为结束标志。 
    返回值:状态码,OK表示操作成功 
    作用:(生成串)生成一个其值等于chars的串T
*/
Status StrAssign(SString T, char *chars){

    int i;

    //越界判断,判断串长是否超过最大值 
    if(strlen(chars) > MAXSTRLEN){

        //操作失败 
        return ERROR;
    }//if
    else{
        //0号存储单元存储了串的长度 
        T[0] = strlen(chars); 

        //复制chars指向的字符串的内容到串T 
        for(i = 1; i <= T[0]; i++) {

            //i是从1开始的,所以要-1,因为chars的字符数据是从0开始的
            T[i] = *(chars + i - 1);  
        }//for 

        //操作成功 
        return OK;
    }//else 
}//StrAssign

/*
    函数:StrCopy
    参数:SString T 复制后得到的串(目的地) 
          SString S 被复制的串(源) 
    返回值:无
    作用:(串拷贝)由串S复制得到串T
*/
void StrCopy(SString T, SString S){

    //以串S为基准 
    for(int i = 0; i <= S[0]; i++){

        //串S和串T相同位置对拷 
        T[i] = S[i]; 
    }//for 
}//StrCopy 

/*
    函数:StrEmpty
    参数:SString S 目标串 
    返回值:状态码,TRUE表示串S是空串,ERROR表示串S不是空串 
    作用:(判空串)若S为空串,则返回TRUE,否则返回FALSE
*/
Status StrEmpty(SString S){

    //0号存储单元记录了串的长度 
    if(S[0] == 0) { //串空 
        return TRUE;
    }//if
    else {
        return FALSE;   
    }//else
}//StrEmpty

/*
    函数:StrCompare
    参数:SString S 被比较串1 
          SString T 被比较串2
          串S和串T必须存在
    返回值:若S > T,返回值 > 0 ,若S = T,返回值 = 0,若S < T,返回值 < 0
    作用:(串比较)串S和串T比较,判断大小的依据是ASCII码。 
*/
int StrCompare(SString S, SString T){

    //如果两串串长相等,则逐个比较每个字符 
    for(int i = 1; i <= S[0] && i <= T[0]; ++i) {

        //通过对两个串中对应位置字符的ASCII码值作差进行比较 
        if(S[i] != T[i]) {
            return S[i] - T[i];
        } //if
    } //for

    //如果两串串长不相等,则直接返回两串串长之差 
    
  • 3
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值