四、串(字符串)

一、定义

串,即字符串,是由零个或多个字符组成的有限序列,一般记为S = ‘a1 a2 a3 … an’,S为串名,单引号内的字符序列是串的值,ai可以是字母、数字、其他字符,串中字符的个数n称为串的长度,n = 0为空串。 例如:S = “hello world!”


子串:串的子序列,空串必是子串;
主串:包含子串的串;
字符在主串的位置:字符在串中的序号;
子串在主串的位置:子串的第一个字符在主串的位置;
空串:没有一个字符的串;
空格串:只包含空格的串,一个空格字符占1B,空串不等于空格串;


串是一种特殊的线性表,数据之间呈现线性关系
串的数据对象限定为字符集(中文字符、英文字符、数字字符、标点字符等)

二、基本操作

增删改查通常以子串作为操作对象

1.赋值操作:

StrAssign(&T,chars):把串T赋值为chars

2.复制操作:

StrCopy(&T,S):将串S复制得到串T

3.判空:

StrEmpty(S):若S为空串,则返回true,否则返回false

4.求串长:

StrLength(S):返回串S的元素个数

5.清空:

ClearString(&S):将S清空为空串

6.销毁:

DestroyString(&S):将串S销毁,回收存储空间

7.串联接:

Concat(&T,S1,S2):用T返回由S1和S2连接而成的新串

8.求子串:

SubString(&Sub,S,pos,len):用Sub返回串S的第pos个字符起,长度为len的子串

9.定位:

Index(S,T):若主串S与串T值相同的子串,则返回它在主串S中第一次出现的位置,否则值为0

10.比较:

StrCompare(S,T):若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0
比较方法:
        从第一个字母开始向后依次对比,先出现更大的字母,则此字符大;若相同子串的长串与短串相比,长串更大。

三、串的存储结构

(一)顺序存储:

ch[0]废弃不用,从ch[1]开始

//顺序存储声明一个串(静态存储) 
#define MAXLEN 255//预定最大串长为255 
typedef struct{
	char ch[MAXLEN];//每个分量存储一个字符 
	int length;//串的实际长度 
}SString;

//顺序存储声明一个串(动态分配),需要malloc函数分配空间 
typedef struct{
	char* ch;//按串长分配存储区,ch指向串的基地址 
	int length;
}HString;

(二)链式存储:

/链式存储声明一个串
typedef struct StringNode0{
	char ch;//每个结点存一个字符 
	struct StringNode0* next;
}StringNode0,*String0; 

typedef struct StringNode1{
	char ch[4];//每个结点存多个字符 
	struct StringNode1* next;
}StringNode1,*String1; 

(三)基于顺序存实现的基本操作:

1.串的声明:

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

//顺序存储声明一个串(静态存储) 
#define MAXLEN 255
typedef struct{
	char ch[MAXLEN];
	int length;
}SString;

//顺序存储声明一个串(动态分配) 
typedef struct{
	char* ch;
	int length;
}HString;

//链式存储声明一个串
typedef struct StringNode0{
	char ch;
	struct StringNode0* next;
}StringNode0,*String0; 

typedef struct StringNode1{
	char ch[4];
	struct StringNode1* next;
}StringNode1,*String1; 

2.求子串:

#include <stdio.h>

//顺序存储声明一个串(静态存储) 
#define MAXLEN 255
typedef struct{
	char ch[MAXLEN];
	int length;
}SString;

//求子串
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];//ch[i-pos+1]:当i=pos时,为ch[i],因为舍弃了ch[0] 
	}	
	Sub.length = len;
	return true;
} 

int main(){
	return 0;
}

3.比较操作:

int StrCompare(SString S,SString 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]; /返回负数或0或正数
		}
	}	
} 

4.定位操作

int Index(SString S,SString T){
	SString sub;//暂存子串 
	int n = StrLength(S);
	int m = StrLength(T);
	int i = 1;
	while(i < n-m+1){
		SubString(sub,S,i,m);
		if(StrCompare(sub,T) != 0){
			++i;
		}else{
			return i;
		}
	}
	return 0;
} 

5.代码集合:

#include <stdio.h>

//顺序存储声明一个串(静态存储) 
#define MAXLEN 255
typedef struct{
	char ch[MAXLEN];
	int length;
}SString;

//求子串
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];//ch[i-pos+1]:当i=pos时,为ch[i],因为舍弃了ch[0] 
	}	
	Sub.length = len;
	return true;
} 

//比较
int StrCompare(SString S,SString 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]; 
		}
	}	
}

//求串长
int StrLength(SString S){
	int i = 1;
	while(i < S.length){
		i ++;
	}
	return i;
} 
//定位
int Index(SString S,SString T){
	SString sub;//暂存子串 
	int n = StrLength(S);
	int m = StrLength(T);
	int i = 1;
	while(i < n-m+1){
		SubString(sub,S,i,m);
		if(StrCompare(sub,T) != 0){
			++i;
		}else{
			return i;
		}
	}
	return 0;
} 

int main(){
	return 0;
}

四、字符串模式匹配

(一)字符串的朴素模式匹配算法

1.概念:

在字符串中搜索需要的内容
在这里插入图片描述

2.基本术语:

主串:需要查询的文本
模式串:需要查的内容
字符串模式匹配:在主串中找到与模式串相同的子串,并返回其位置

注意:子串是主串的一部分,但模式串不一定是主串的一部分(匹配不了)

3.实现思想:

暴力方式:依次解决,若模式串长度为6,则在主串中找出所有长度为6的子串,依次和模式串匹配;
在长度为n的主串中,有n-m+1个长度为m的子串,定位操作采用的就是此算法:

int Index(SString S,SString T){
	SString sub;//暂存子串 
	int n = StrLength(S);
	int m = StrLength(T);
	int i = 1;
	while(i < n-m+1){
		SubString(sub,S,i,m);
		if(StrCompare(sub,T) != 0){
			++i;
		}else{
			return i;
		}
	}
	return 0;
} 

通过数组下标实现朴素模式匹配算法:
在这里插入图片描述

int Index1(SString S,SString T){
	int i = 1;
	int 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;//所有子串匹配失败
	}
} 

最好时间复杂度:O(n)
在这里插入图片描述

最坏时间复杂度:O(nm)
在这里插入图片描述

(二)KMP算法:

1.概念:

朴素模式匹配算法,当发现当前子串最后一个字符不匹配,只能转而匹配下一个子串,需要从头开始,但是,当前子串的前几个字符一定是和模式串相匹配的,即可知,若依次移动子串位置时,已匹配的字符不需要再参与匹配(必定不匹配),例如T = ‘abaabc’:


当第6个元素失配
在这里插入图片描述


当第5个元素失配
在这里插入图片描述


当第4个元素失配
在这里插入图片描述


当第3个元素失配
在这里插入图片描述


当第2个元素失配
在这里插入图片描述


当第1个元素失配
在这里插入图片描述


总体而言
在这里插入图片描述


2.C语言实现:

//KMP算法:用数组实现:
int Index_KMP(SString S,SString T,int next[]){//模式匹配部分 
	int i = 1;
	int j = 1;
	while(i <= S.length && j <= T.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;
	}
}

最坏时间复杂度:O(n+m)

3.手动求next数组:

例题一:
在这里插入图片描述模式串相右后移依次,对比除了已经未匹配的其他字符,有一个不匹配则继续右移模式串

例题二(详细过程):


在这里插入图片描述第三个匹配,则在第二个后面划线,模式串右移一位,但a和b无法匹配,则继续右移


在这里插入图片描述第四个匹配,则在第三个后面划线,模式串后移一位,模式串第一个元素a和子串第二个元素b不一样,则模式串继续右移一位,模式串第一个a元素和子串第三个元素a相同,其后在没有位于线左边的模式串元素,则next为2


在这里插入图片描述第五个匹配,则在第四个后面划线,模式串后移一位,模式串第一个元素a和子串第二个元素b不同,则模式串继续右移一位,模式串第一个元素a和子串第三个元素a匹配,模式串第二个元素b和子串第四个元素b相同,则next为3


在这里插入图片描述


例题三:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值