【数据结构笔记】串(顺+链)+朴素算法+KMP算法

#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 255			//静态数组最大容量;若用ch[0]记录串长,1个字节范围0~255,即字符串长度不能超过255 
#include <iostream>
using namespace std;

//串,字串string,即字符组成的有限序列,是特殊的线性表,串一般只存储字符 
//子串:串中任意连续字符组成的子序列;主串;字符编号从1开始,子串的位置以第一个字符的位置为准,1个空格=1字节(1B)=8比特(bit)
 

/*串(顺序存储)*/ 
typedef struct{
	char ch[MAXLEN];
	int length;		//定长的顺序存储(静态数组),对于静态数组存放串,默认ch[0]放弃不用,从ch[1]开始储存字符串,另外单独用变量length记录字符串长度(不含ch[0]) 
}SString;

typedef struct{
	char *ch;
	int length;
}HString;

void InitStr(HString &S){
	S.ch = (char *)malloc(sizeof(char));		//这片空间需要free,这片空间是动态的 
	S.length=0;
};

/*串(链式存储)*/
typedef struct StringNode{
	char ch[4];			//每个结点存放四个字节,提高存储密度 
	struct StringNode *next;		//存放指向下个结点的指针(1个指针占4个字节),存储密度低 
}StringNode, *String; 

/*基本操作*/

//求子串
bool SubString(SString &Sub, SString S, int pos, int len){
	if(pos+len-1>S.length)
		return false;
	for(int i=pos; i<pos+len; i++)
		Sub.ch[i-pos+1]=S.ch[i];
	Sub.length=len;
	return true;
} 

//比较字符串操作 
int StrCompare(SString S,SString T){		//当return值为正,S>T;return为0,S=T;return为负,S<T 
	for(int i=1;i<S.length&&i<T.length;i++){
		if(S.ch[i]!=T.ch[i])
			return S.ch[i]-T.ch[i];
		}
	return S.length=T.length;		//扫描过的所有字符都相同,则长度长的串更大 
}
 
//定位操作,若主串S中存在与T相同的子串,则返回子串第一次出现的位置,否则返回值为0; 
int Index(SString S,SString T){
	int n=S.length, m=T.length, i=1;
	SString Sub;		//用于暂存子串 
	while(i<n-m+1){
		SubString(Sub,S,i,m);
		if(StrCompare(Sub,T)!=0)	++i;		//子串不等,位置往后移1位继续对比 
		else return i;		//找到相等子串,返回其位置i 
	}
	return 0;		//while循环结束后仍然无输出,则S中没有与T相等的子串,返回0 
} 

//朴素模式匹配算法,指针i多次回溯,增加时间成本 
int Index2(SString S,SString T){
	int k=1,j=1,i=k;
	while(i<=S.length&&j<=T.length){
		if(S.ch[i]==T.ch[j]){
			++i;
			++j;
		} else{
			k++;		//一旦有相同子串扫描到,循环中止 
			i=k;
			j=1;
		}
	}
	if(j>T.length)		//只有在主串找到与模式串相等的子串,j才会>T.length 
		return k;
	else
		return 0;
} 

//KMP算法~手算next数组;S主串,T模式串 
//next数组指的是当模式串扫描到第j个发现与主串不匹配时,j指针跳到第next[j]个处重新扫描;
//手算规则是:寻找T的前缀子串=S的后缀子串,记这个子串为S,next[j]=S长度+1;注意前缀子串不含最后一个元素,后缀子串不含第一个元素
//next[1]=0, next[2]=1; j=1不匹配时,i++,j++,next[j]=0 

//KMP算法(在子串仅能部分匹配时表现比朴素算法好,避免主串指针i回溯) 
int Index_KMP(SString S,SString T,int next[]){
	int i=1,j=1;		//字符串从1开始储存元素(ch[0]为空)
	while(i<=S.length&&j<=T.length){		//字符串长度不包括ch[0]的部分 
		if(j==0||S.ch[i]==T.ch[j]){
			i++; j++;
		}
		else
			j=next[j];	//模式串指针向右移动,避免回溯 
	}
	if(j>T.length)		//代表模式串已遍历对比,主串中有相同子串 
		return i-T.length;
	else
		return 0;		//主串已遍历对比,没有匹配模式串的 
}

//KMP算法的优化-->nextval数组,当字符串前面有相同的元素,从next[0]开始从左往右确定nextval[]的值
//nextval数组替代next数组,避免相同元素重复匹配 

void nextVal(SString T,int next[]){
	int nextval[T.length];
	for(int j=2;j<=T.length;j++){
		if(T.ch[next[j]]==T.ch[j])
			nextval[j]=nextval[next[j]];
		else
			nextval[j]=next[j];
	}
} 


 


int main(){
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值