数据结构第四章字符串部分代码c

在c语言中虽然没有明确的string类型,而是用char[]来表征字符串,但是却有字符串相关的一些库函数#include<string.h>可以直接使用。所以这一部分除了KMP没有可看性,但是这里的KMP只有代码无思路,非大佬可以看懂,所以这一文章除非要copy KMP代码,否则没有可看性,慢走不送。

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>

/*
1	strcpy(s1, s2);
复制字符串 s2 到字符串 s1。
2	strcat(s1, s2);
连接字符串 s2 到字符串 s1 的末尾。
3	strlen(s1);
返回字符串 s1 的长度。
4	strcmp(s1, s2);
如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。
5	strchr(s1, ch);
返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6	strstr(s1, s2);
返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
7   void *memchr(const void *str, int c, size_t n)
在字符串str中前n个字符中搜索第一个出现字符c的位置
*/
void demo(){
    char str1[14]="hello!";
    char str2[14]="cch";
    char str3[14]="";
    int len=0;
    strcpy(str3,str1);//复制str1到str3
    printf("%s\n",str3);

    strcat(str1,str2);//连接str2到str1
    printf("%s\n",str1);

    len=strlen(str1);//求str1长度
    printf("%d\n",len);

    char *result=" ";
    result=(char*)memchr(str1,'h',0);//找不到,空的,因为n=0
    printf("%s\n",result);
    result=(char*)memchr(str1,'e',4);//找得到,并且输出的是包含e之后的所有字串
    printf("%s\n",result);

}

顺序存储结构

#ifndef HSTRING_H
#define HSTRING_H

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
/**
 * @brief 串的顺序存储结构
 * 
 */
#define MaxLen 255
// 静态数组实现定长顺序存储
typedef struct{
    char ch[MaxLen];
    int len;
}SString;

// 动态数组实现,堆分配存储,需要手动free
typedef struct{
    char *ch;//按串长分配存储区,ch指向串的基地址
    int length;
}HString;
// HString s;
// s.ch=(char *)malloc(MaxLen*sizeof(char));
// s.length=0;
#endif

链式存储结构

#ifndef LISTRING_H
#define LISTRING_H
#include<stdlib.h>
#include<stdbool.h>
#include<stdio.h>
/**
 * @brief 串的链式存储结构
 * 
 */
typedef struct StringNode2{
    char ch;//每一个结点存储1个字符
    struct StringNode2 *next;//需要4个字符来存储一个指针,存储密度低
}StringNode2,*String2;

typedef struct StringNode{
    char ch[4];//每一个结点可以存储多个字符,提高存储密度
    struct StringNode *next;
}StringNode,*String;

#endif

  • 顺序存储结构的实现
#include "hstring.h"

bool SubString(SString *sub,SString s,int pos,int len){
    // 字串范围越界
    if(pos+len-1>s.len)
        return false;
    // 注意pos表示的是位序,对应于数组元素需要-1
    for(int i=pos-1;i<pos+len-1;i++){
        (*sub).ch[i-pos+1]=s.ch[i];
    }
    (*sub).len=len;
    
    return true;
}
int StrCompare(SString s,SString t){
    for(int i=0;i<s.len&&i<t.len;i++){
        // 对应字符的元素不同
        if(s.ch[i]!=t.ch[i])
            return s.ch[i]-t.ch[i];
    }
    // 扫描所有的字符都相同,长度大的串更大
    return s.len-t.len;
}
// 定位操作,如果主串中存在于串T相同的字串,返回它在主串中第一次出现的位置(数组下标+1),否则返回0
int Index(SString s,SString t){
    int i=0;
    int n=s.len;
    int m=t.len;
    SString sub;
    while(i<(n-m)){
        SubString(&sub,s,i+1,m);
        if(StrCompare(sub,t)!=0)
            i++;
        else
            return i+1;
    }
    return 0;//不存在与t相等的字串

}
void PrintfString(SString s){
    for(int i=0;i<s.len;i++){
        printf("%c",s.ch[i]);
    }
    printf("\n");
}
  • 朴素模式匹配
// ---------------------华丽的分界线-----------------------------
// 后面的操作都采用舍弃第一个空间[0]号的元素,使得位序和数组的存储下标一致
// 朴素模式匹配
int simpleMatch(SString s,SString t){
    int i=1,j=1;
    while(i<=s.len&&j<=t.len){
        if(s.ch[i]==t.ch[j]){
            i++;
            j++;
        }else{
            i=i-j+2;
            j=1;
        }
    }
    if(j>t.len)
        return i-t.len;
    else
        return 0;
}
int simpleMatch1(SString s,SString t){
    int i=1,j=1;
    int n=s.len,m=t.len;
    while(i<n-m+1){
        while(j<=m){
            if(s.ch[i]!=t.ch[j]){
                i=i-j+2;
                j=1;
                break;//恢复i,j的数据,结束本轮循环进行下一轮匹配
            }else{
                i++;
                j++;
            }
        }
        if(j>m){//说明匹配成功,返回字串第一个下标
            return i-j+1;
        }
    }
    return 0;
}
void test1(){
    SString s;
    strcpy(s.ch," Today is Monday!");//不能直接给ch赋值,只能使用c中自带的字符串函数
    s.len=16;

    // SString sub;
    // SubString(&sub,s,10,5);
    // PrintfString(sub);

    // printf("%d\n",StrCompare(s,sub));
    // printf("%d\n",Index(s,sub));
    SString t;
    strcpy(t.ch," today");
    t.len=5;
    printf("%d\n",simpleMatch1(s,t));
    printf("%d\n",simpleMatch(s,t));
}
void main(){
    test1();
}
  • KMP

找个视频看思路吧,看代码看不懂的,单纯一个数学题写成的一个代码


// KMP开始前需要对模式串预处理,先求next数组,再利用next数组进行匹配
// 模式向后滑动的计数仅和模式本身结构有关,和主串无关,说明next是不依赖与主串的数组
// 主串的指针不回溯,时间复杂度为O(n+m)

// 求KMP的next数组
void KMPnext(SString t,int next[]){
    int i=1,j=0;
    next[1]=0;
    while(i<t.len){
        if(j==0||t.ch[i]==t.ch[j]){
            i++;
            j++;
            next[i]=j;
        }else
            j=next[j];
    }

}
// 求KMP的nextVal数组
void LMPnextVal(SString t,int nextVal[]){
    int i=1,j=0;
    nextVal[1]=0;
    while(i<t.len){
        if(j==0||t.ch[i]==t.ch[j]){
            i++;
            j++;
            if(t.ch[i]!=t.ch[j])
                nextVal[i]=j;
            else
                nextVal[i]=nextVal[j];

        }else
            j==nextVal[j];
    }
}
int KMP(SString s,SString t,int next[]){
    int i=1,j=1;
    while(i<s.len&&j<t.len){
        if(j==0||s.ch[i]==t.ch[j]){
            i++;
            j++;
        }else
            j=next[j];

    }
    if(j>t.len)
        return i-t.len;
    else
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值