【数据结构五】串的基本知识和字符串的模式匹配两种算法(暴力/KMP)

定义:即字符串,是由零个或多个字符组成的有限序列。

是一种特殊的线性表,数据元素之间呈现线性关系

串的数据对象限定为字符集(如中文字符、英文字符、数字字符、标点字符等)

串的基本操作:如增删改查通常以子串为操作对象

空串 VS 空格串 M='' :是空串 N=' ' :是由3个空格字符组成的空格串,每个空格字符占1B,即8bit

乱码问题???

原因: 编写和打开文件时使用的编码规则不一样

串的存储结构

  • 顺序存储:
arduino 复制代码
//---------串的顺序存储
 #define MAXLEN 255 //预定义最大串长为255
//(静态数组实现) 
typedef struct{
	char ch[MAXLEN]; //每个分量存储一个字符
	int length; //串的实际长度 
}SString;
//求字串:用Sub返回串S的第pos个字符起长度为len的字串 
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;
} 
//比较两个串的大小:若S>T,返回值>0;若S=T,返回值=0;若S<T,返回值<0
int StrCompare(SString S, SString T){
	for(int i = 0; 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; 
}
//求子串长度
int StrLength(SString S){
	return S.length;
}
//定位操作。若主串S中存在与串T值相同的字串,则返回它在主串S中第一次
//出现的位置,否则函数值为0;
int Index(SString S, SString T){
	int i = 1, n = StrLength(S), m = StrLength(T);
	SString sub; //用于暂存子串
	while(i <= n-m+1){
		SubString(sub, S, i, m);
		if(StrCompare(sub, T) != 0) ++i;
		else return i; //返回子串在主串中的位置 
	} 
	return 0; //S中不存在与T相等的字串 
} 


//动态数组实现(堆分配存储) 
typedef struct{
	char *ch; //按串长分配存储区,ch指向串的基地址
	int length; //串的长度 
}HString; 

//----------串的链式存储
typedef struct StringNode{
	char ch[4]; //每个结点存多个字符
	struct StringNode * next; //(指针占4b) 
}StringNode, * String; 

int main(int argc, char** argv) {
	HString S;
	S.ch = (char *)malloc(MAXLEN * sizeof(char));
	S.length = 0; 
	return 0;
}

字符串模式匹配------------朴素模式匹配算法(暴力解决)

  • 主串长度为n,模式串长度为m
  • 解决:将主串中所有长度为m的子串 依次与模式串对比,(最多对比n-m+1个子串),直到找到一个完全匹配的字串,或所有的子串都不匹配为止。
  • 上面的那个定位操作 就是实现了用字符串的基本操作来实现朴素模式匹配算法。
  • 下面用数组下标来实现朴素模式匹配算法:
ini 复制代码
// 数组下标实现模式匹配
int Index2(SString S, SString T){
	int i = 1, j = 1;
	while(i <= S.length && j <= T.length){
		if(S.ch[i] == T.ch[j]){
			++i;
			++j; //继续匹配后继字符 
		}
		else {
			i = i-j+2;
			j = 1; //指针后退重新开始匹配 
		} 
	}
	if(j > T.length)
		return i-T.length;
	else 
		return 0;
} 
  • 设主串长度为n,模式串长度为m,则最坏时间复杂度 = O(nm)。最坏的情况,每个子串都要对比m个字符,共n-m+1个子串,复杂度 = O((n-m+1)m) = O(nm)

字符串模式匹配------------KMP算法(对朴素模式匹配算法的优化)

ini 复制代码
//KMP算法
int Index_KMP(SString S, SString T, int next[]){
	int i = 1, j = 1;
	while(i <= S.length && j <= S.length){
		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; 
}
//求模式串T的next数组(这个有待研究)
void get_next(SString T, int next[]){
	int i = 1, j = 0;
	next[1] = 0;
	while(i < T.length){
		if(j == 0 || T.ch[i] == T.ch[j]){
			++i;
			++j;
			//若pi=pj, 则next[j+1] = next[j] + 1
			next[i] = j; 
		}
		else
			//否则令j = next[j],循环继续
			j = next[j];
	}
} 

//求nextVal数组:先求next数组,再由next数组求nextVal数组
int[] get_nextVal(SString T, int next[]){
    int nextval[T.length + 1];
    nextval[1] = 0;
    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];
        }
    }
    return nextval[];
}

//KMP算法(主串中的i指针不回溯,模板串中的j回溯)
int Index_KMP2(SString S, SString T){
	int i = 1, j = 1;
	int next[T.length + 1];
	get_next(T, next); //求模式串的Next数组
	while(i <= S.length && j <= T.length){
		if(j == 0 || S.ch[i] == T.ch[j]){
			++i;
			++j;
		}
		else
			j = next[j]; //j指针回溯
	} 
	if(j > T.length)
		return i-T.length; //匹配成功
	else 
		return 0; 
} 
相关推荐
韭菜盖饭2 小时前
LeetCode每日一题3261---统计满足 K 约束的子字符串数量 II
数据结构·算法·leetcode
♡喜欢做梦2 小时前
【数据结构】ArrayList与LinkedList详解!!!——Java
java·开发语言·数据结构·链表
好心的小明3 小时前
【深圳大学】数据结构A+攻略(计软版)
数据结构
熬夜学编程的小王3 小时前
【初阶数据结构篇】插入、希尔、选择、堆排序
数据结构·c++·插入排序·选择排序·希尔排序
三小尛3 小时前
快速排序(C语言)
数据结构·算法·排序算法
椅子哥3 小时前
数据结构--排序算法
java·数据结构·算法·排序算法
DDDiccc3 小时前
JAVA学习日记(十五) 数据结构
数据结构·学习
Nydia.J3 小时前
【学习笔记】数据结构(七)
数据结构·考研
2301_799084673 小时前
超全排序C语言实现
c语言·数据结构·算法·排序算法
苏唱!!!!3 小时前
二叉树-堆
数据结构