串
在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;
}