【数据结构】-- 串(BF、KMP算法)

计算机上的非数值处理的对象大部分是字符串数据,字符串一般简称为串(string)

串的定义

串(string)(或字符串)是由零个或多个字符组成的有限序列。

串的概念解释:

  • 空串(null string):零个字符的串。
  • 子串:串中任意个连续的字符组成的子序列,子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。
  • 主串:包含子串的串相应的称为主串。
  • 空格串:只包含空格的串
  • 相等串:位数相等,对应每个位置的字符相同

串的抽象类型定义

串的逻辑结构和线性表相似,区别仅在于串的数据对象约束为字符集。然而,串的基本操作和线性表有很大区别。在线性表中通常以“单个元素”作为操作对象;而在串中,通常以“串的整体”作为操作对象

ADT String
{
	Data 
		串中元素仅由一个字符组成,有前驱后继的关系
	Operation
		StaAssign(&T,chars)	生成一个其值等于chars的串T
		StrCopy(&T,S)	由串S复制得串T
		ClearString(&T)	将串T清空
		StrEmpty(S)		若串S为空,返回true
		StrCompare(S,T)	 若S>T 其返回值大于0,S=T 返回值=0,S

串的存储结构

1、串的顺序存储结构

类似于线性表,用一组地址连续的存储单元存储串值的字符序列。

-----串的定长顺序存储结构-----
#define MAXLEN 255
typedef struct{
	char ch[MAXLEN+1];		//存储串的一维数组
	int length;			//串的当前长度 
}SString; 

注:以上定义方式是静态的,再编译的时候就确定了串的空间大小。根据实际需要,串的变化是很大的,因此最好的是在程序执行过程中动态的分配和释放字符数组空间。所以有了——“堆”(Heap)

------串的堆式存储结构------ 
typedef struct{
	char *ch;	        //若是非空串,则按串长分配存储区,否则ch为NULL
	int length;		//串的当前长度 
}HString;

2、串的链式存储结构

对于串结构的特殊性——结构中的每个数据元素是一个字符,则在链表存储串值时,会造成空间的利用率不足、即“结点大小”的问题。每个结点可以存储一个字符,也可以存放多个字符

------串的链式存储结构------
#define CHUNKSIZE 80		//可由用户定义的块大小
typedef struct Chunk{
	char ch[CHUNKSIZE];
	struct Chunk *next;
}Chunk;
typedef struct{
	Chunk *head,*tail;	//串的头尾指针
	int length;		//串的当前长度 
}LString; 

特此声明:以下算法均利用串的顺序存储模式进行示例。


串的模式匹配算法

子串的定位运算通常称为串的模式匹配或串匹配。

假设我们要从主串S=“goodgoogle”,找到T=“google”这个子串的位置。如果匹配成功,则返回子串的第一个字符在主串中的位置。所以有了两种著名的算法:BF算法与KMP算法

模式匹配算法不一定从第一个位置开始,可以指定主串中查找的起始位置pos。

1、BF算法(Brute-Force)     O(m*n)

特点:古典、直观、经典、朴素、穷举的

【算法步骤】

①分别利用计数指针i与j 分别指向pos与1。

②当i<=S.length并且j<=T.length时执行以下操作

  • 如果i指向S当前字符等于j指向T当前字符,则i和j分别指向下一个位置。
  • 否则,i和j归位即 (i=i-j+2)

③若j大于T的长度,那么匹配成功,返回i-T.length,否则返回0

int Index_BF(SString S,SString T,int pos)
{
	int i=pos,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;
}

【算法分析】

注:这次没有gif……懒得做了……所以我用了excel  哈哈哈哈

BF算法匹配步骤
第一趟匹配 g o o d g o o g l e
g o o g l e        
第二趟匹配 g o o d g o o g l e
  g o o g l e      
第三趟匹配 g o o d g o o g l e
    g o o g l e    
第四趟匹配 g o o d g o o g l e
      g o o g l e  
第五趟匹配 g o o d g o o g l e
        g o o g l e

由上图可知,最好的情况是从第一个字符就匹配成功了,最坏的情况就如上表所示,到最后才匹配成功。所以可得BF算法的时间复杂度:O(m*n)。

2、KMP算法     O(m+n)

KMP算法是由Knuth、Morris和Pratt同时设计的,因此简称KMP算法。这种算法进行了改进,时间效率提高了许多。

KMP算法分为了两个部分,第一个部分是求next[],第二个部分是匹配……,相比较于BF算法,KMP算法省略了上表的第二、三、四趟比较。并且指向主串的指针不回溯。。所以kmp算法的精力主要集中在 子串的处理。。来吧……上代码……

//计算next函数值 
void get_next(SString T,int next[])
{
	int i=1,j=0;
	next[1]=0;
	while(iT.length)	
		return i-T.length;
	else
		return 0;
}

等等!!!结尾附上next函数定义:


博客内容借鉴于:

①《数据结构》  作者:严蔚敏

②《大话数据结构》 作者:程杰

你可能感兴趣的:(数据结构)