数据结构与算法整理3——BP算法和KMP算法

核能气质少年 提交于 2020-02-13 17:12:01

数据结构与算法整理3——BP算法和KMP算法

目录

数据结构与算法整理3——BP算法和KMP算法

1、字符串的基本操作

2、模式匹配——BP算法和KMP算法

3、串的操作代码(C语言)


1、字符串的基本操作

1)串的定义:字符串(也就是串)是0个或多个字符序列组成的有限序列。

  • 串就是数据元素为单个字符的特殊线性表。
  • “qhjkdcbjsb”(隐含结束符\0)就是一个字符串,引号起界定作用,“”表示空串,串长为0
  • “  ”空格串不是空串,串长为空格数。

2)串的存储类型:顺序存储:定长顺序存储结构、堆分配存储结构(动态分配连续内存)

      链式存储:

 

2、模式匹配——BP算法和KMP算法

串的模式匹配:就是指定一个主串S和子串T,求T在S中第一次出现的位置。

(1)朴素模式匹配(BP算法)

核心思想:主串S和子串T,S[1]和T[1]比较,S[2]与T[2]比较,直到S[n]与T[n]都是相等的为止,若S[i]与T[i]不相等,则子串向右移动一个(一个字符)继续比较。

时间复杂度:主串S长度为n,子串T长度为m,最多进行m(m-n+1)次,最坏的时间复杂度为O(mn) 效率不高。

(2)KMP算法

核心思想:尽量利用已经得到的“部分匹配”的结果信息,不要让i回溯,加快子串右滑的速度,问题由子串决定而不是主串决定的

next数组:是一个智能数组,指导子串下一步改用几号元素去匹配,next数组的next[1]和next[2]永远为0和1,其余next[n]看n位的前后缀的相同数目

实例:a、现有子串i=“ABABAAABA”,求其next数组

i

9

a

b

a

b

a

a

a

b

a

j

0

1

2

3

4

5

6

7

8

9

next

 

0

1

1

2

3

4

2

2

3

 

Next数组中对应i数组的值

前缀

后缀

Next[]的值

Next[j1]

0

0

0

Next[j2]

A

A

1

Next[j3]

A

B

1

Next[j4]

A

A

2

Next[j5]

AB

AB

3

Next[j6]

ABA

ABA

4

Next[j7]

A

A

2

Next[j8]

A

A

2

Next[j9]

AB

AB

3

b、实例,不详细解释,主串是S=“bbsbbcdfbb”子串是“bbsbbs”,求next数组?

T

6

b

b

s

b

b

s

J

0

1

2

3

4

5

6

next

 

0

1

2

1

2

3

c、主串是S=“sssssvsd”,子串是T=“ssssb”求next数组?

S

5

s

s

s

s

B

l

0

1

2

3

4

5

Next

 

0

1

2

3

4

Next数组中对应i数组的值

前缀

后缀

Next[]的值

Next[j1]

0

0

0

Next[j2]

s

s

1

Next[j3]

s

s

2

Next[j4]

ss

ss

3

Next[j5]

sss

sss

4

KMP算法的时间复杂度:O(m+n)

 

3、串的操作代码(C语言)

#include <stdio.h>
#include <malloc.h>
#include <string.h>
 
typedef struct
{
	char *ch;  //定义一个数组来存放串 char ch[max](有最大的长度)等价于 char *ch (空串时指向NULL,非空串时按串长分配存储区) 
	int len;    //定义串的长度 
}PSeqString;  

int initialstring(PSeqString *t)   //为串初始化,初始化的目的是确保串能都得到正确的空间分配, 
{
	t->ch=NULL;
	t->len=0;
	return 1;
 } 

int assign(PSeqString *t,char *p) //把字符串P的值赋给串PSeqString t  char  *p想打昂与char p[] 
{
	int i,length=strlen(p);   
	if(t->ch)              //如果字符串t已有内容则释放t的内容 
	free(t->ch);
	if(!length)              //判断赋值的 p[]数组是否为空,为空的话就直接吧串赋值为NULL;len=0 
	{
		t->ch=NULL;
		t->len=0;
		return 0;
	}
	else
	{
		t->ch=(char *)malloc (length *sizeof(char));        //为每一个字符串申请长度 要乘以字符串的长度length  然后强制转换为char 类型 返回给一个指针 
		if(!t->ch)              
		return 0;
		for(i=0;i<length; ++i)
		{
		t->ch[i]=p[i];
		}
		t->len=length;	      // 赋值t->len 
		return 1;
	}
 } 
 
void  prinfstring(PSeqString T)  //循环遍历 输出串T  
 {
 	int i;
 	for(i=0;i<T.len;++i)
 	{
 		printf("%c",T.ch[i]);
	 }
	 printf("\n");
 }

int stringInsert (PSeqString *s,int pos,PSeqString t) //在串s中下标为pos的字符之前插入串t;
{
    int i;
    char *temp; 
    if(pos<0 || pos>s->len||s->len==0) return 0;  //插入位置不合法
    temp=(char*)malloc (s->len+t.len); 
    if(temp==NULL) return 0;
    for(i=0;i<pos ;i++)
    temp[i]=s->ch[i];
	for(i=0;i<t.len;i++)
      temp[i+pos]=t.ch[i];
    for(i=pos;i<s->len;i++)
      temp[i+t.len]=s->ch[i];
    s->len+=t.len ;
    free(s->ch);
    s->ch=temp;
    return 1;
}

int addstring(PSeqString *T ,PSeqString s1,PSeqString s2)//将字符串s1  s2连接
{
	int i;
	if(T->ch)
	free(T->ch);
	T->ch=(char *)malloc ((s1.len+s2.len)*sizeof(char));
	if(!T->ch)
	return 0;
	for (i=0;i<s1.len;++i)  //先把s1的值赋值给T,再把s2的值赋给T 
		T->ch[i]=s1.ch[i];
	for(i=0;i<s2.len;++i)
		T->ch[i+s1.len]=s2.ch[i];
	T->len=s1.len+s2.len;
	return 1;
 } 
int main()
{    
	PSeqString s,t,T;
	int i,pos=1;
	char *p="asc";
	char *q="jkb";
    initialstring(&t);
    initialstring(&s);
    assign(&t,p);
    assign(&s,q);
    prinfstring(t);
    prinfstring(s);
    stringInsert (&t,pos,s);
    prinfstring(t); 
    addstring(&T ,s,t);
	prinfstring(T);
   
}

运行结果如下:

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!