数据结构-串
发布日期:2021-05-04 03:07:39 浏览次数:31 分类:原创文章

本文共 3578 字,大约阅读时间需要 11 分钟。

1.串的定义

 串是仅有字符构成的有限序列,是一种线性表。一般记为S='a1a2...an',其中,S是串名,单引号括起来的字符序列是是串值。

2.串的几个基本概念

1)空串:长度为零的串。

2)空格串:由一个或多个空格组成的串,空格也是一个字符。

3)子串:由串中任意长度的连续字符构成的序列,含有子串的串称为主串。子串在主串中的位置是指子串首次出现时,该子串的第一个字符在主串中的位置。空串是任意串的子串。

3.串的基本操作

1) 初始化

#define MAX_SIZE 100typedef struct{	char *ptr;  //串存放的起始地址	int length; //串的长度}String;int init(String *str){	str->length = 0;	str->ptr = (char *)malloc(MAX_SIZE * sizeof(char));	if (str->ptr)	{		return 0;	}	else	{		return -1;	}}

2) 判断空

bool isEmpty(String* str){	if (str->length == 0)	{		return true;	}	else	{		return false;	}}

3)赋值

void strAssign(String *str, char ch[]){	int i = 0;	//计算第二个字符串的长度	while (ch[i] != '\0')	{		i++;	}	str->length = i;	if (i > MAX_SIZE)	{		str->ptr = (char *)realloc(str->ptr, i+1);	}	for (i = 0; i < str->length; i++)	{		//从第一个字符开始,着个赋值		str->ptr[i] = ch[i];	}	str->ptr[str->length] = '\0';}

4)连接 

void Concat(String* s1, char ch[]){	int i = 0;	//计算第二个字符串的长度	while (ch[i] != '\0')	{		i++;	}	//判断总共有多少字符,如果大于最大则重新申请空间,再赋值	int totalSize = s1->length + i;	if (totalSize <= MAX_SIZE)	{		for (int j = 0; j < i; j++)		{			s1->ptr[s1->length + j] = ch[j];		}		s1->ptr[totalSize] = '\0';	}	else	{		s1->ptr = (char *)realloc(s1->ptr, totalSize + 1);		for (int j = 0; j < i; j++)		{			s1->ptr[s1->length + j] = ch[j];		}		s1->ptr[totalSize] = '\0';	}}

4)串的模式匹配

(1)布鲁特-福斯算法(BF)

从主串的第一个字符起与模式串的第一个字符比较,如果相等,则继续逐一对字符串的字符进行后续比较;如果不相等,则从主串第二个字符起与模式串的第一个字符重新比较,直到模式串中每个字符依次和主串中一个连续的字符序列相等为止,此时匹配成功;否则,匹配失败。

//从pos开始的位置,查找模式串t在主串s串中是否存在int index(char s[],char t[],int pos){    //i,j分别用于指出主串字符和模式串字符的位置    int i,j;    int sLen,tLen;    i = pos;    j = 0;    sLen = strlen(s);    tLen = strlen(t);    while(i < sLen && j < tLen)    {        if(s[i] == t[j])        {            i++;            j++;        }        else        {            i = i-j+1;            j = 0;        }    }    if(j >= tLen)    {        return i-tLen;    }    return -1;}

(2)KMP算法

改进之处在于,每当匹配过程中出现相比较的字符不相等时,不需要回退主串的字符指针位置,而是利用已经得到的“部分匹配”结果将模式串向右“滑动”尽可能远的距离,再继续进行比较。在KMP算法中,依据模式串的next函数值实现子串的滑动。

模式串 a b a b a b b
下标 0 1 2 3 4 5 6
next数组 -1 0 0 1 2 3 4

解析:abababb,一个一个字符看,教大家一个方法,看除去最后一个字符的前两个字符。

默认next[0] = -1

ab:除去最后一个字符b,前面a,没有相同的前缀和后缀,则next[1] = 0;

aba:除去最后一个字符a,前面ab,没有相同的前缀和后缀,则next[2] = 0;

abab:除去最后一个字符b,前面aba,有相同的字符a ,next[3] = 0 + 1 =1;

ababa:除去最后一个字符a,前面abab,有相同的前缀和后缀ab,next[4] = 0+2 = 2;

ababab:除去最后一个字符b,前面ababa,有相同的前缀和后缀aba,next[5] = 0+3 = 3;

abababb:除去最后一个字符b,前面ababab,有相同的前缀和后缀abab,next[4] = 0+4 = 4;

以下为获取next函数的算法:

void get_next(char *p,int next[]){    int i,j,sLen;    sLen = strlen(p);    i = 0;    next[0] = -1;    j = -1;    while(i < sLen)    {        if(j == -1 || p[i] == p[j])        {            ++i;            ++j;            next[i] = j;        }        else        {            j = next[j];        }    }}

以下为KMP算法:

//利用模式串p的next函数,从第pos个字符开始,求p在主串s中是否存在int KMP(char *s,char *p,int pos,int next[]){    int i;    int j;    int sLen;    int pLen;    i = pos -1;    j = -1;    sLen = strlen(s);    pLen = strlen(p);    while(i < sLen && j < pLen)    {        if(j == -1 || s[i] == p[j])        {            ++i;            ++j;        }        else        {            j = next[j];        }    }    if(j >= pLen)    {        return i-pLen;    }    else    {        return -1;    }}

以下为KMP算法示意图: 

KMP算法的示意图

①第一次匹配从S[0]与P[0]开始,由于S[0]==P[0],S[1]==P[1],S[2]==P[2],比较S[3]和P[3],由于它们不相等,所以第一次匹配结束

②第二次匹配,令j = next[3] = 1,第二次从S[3]与P[1]开始比较,仍不相等,则第二次匹配结束

③第三次匹配,令j = next[1] = 0,第三次从S[3]与P[0]开始比较,仍不相等,则第三次匹配结束

④第四次匹配,令j = next[0] = -1,此时满足条件“j == -1”,显然不能令S[3]与P[-1]进行比较,说明主串中从i = 3开始的字串不可能与模式串相等,因此需要将 i 的值递增后再继续进行匹配,令i++,j++;

⑤第五次匹配,S[4]与P[0]比较,直到匹配完成

上一篇:Qt 圆形进度条实现
下一篇:数据结构-队列

发表评论

最新留言

不错!
[***.144.177.141]2025年03月19日 23时26分25秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章