大话数据结构10串

 1、串的定义:是由零个或多个字符组成的有限序列,又叫字符串

  序列,说明串的相邻字符之间具有前驱和后继的关系;长度n即串中的字符数,n为0则为空串。

  空格串,是只包含空格的串,是有内容有吃的的,而且可以不止一个空格。

  子串与主串,串中任意个数的连续字符组成的子序列称为子串,包含子串的串称为主串。

  子串在主串中的位置就是子串的第一个字符在主串中的序号。

2、串的比较:通过比较组成串的字符之间的编码,字符的编码是指字符在对应字符集中的序号(如ASCII码)。

  标准的ASCII码:由7位二进制数表示一个字符,总共可以表示128个字符;扩展ASCII码:由8位二进制数表示一个字符,总共可以表示256个字符;Unicode编码:由16位的二进制数表示一个字符。为了和ASCII码兼容,Unicode的前256个字符与ASCII码完全相同。

  两个串相等的条件:两个串的长度以及各个对应位置的字符都相等。

  两个串不相等如何判断大小:1、若有一个串长度较大,且长度为n的短串完全与其前n个字符相等,则长串大;2、如果在依次比较时,某一个串有一个字符的值大,则该串大。

3、串的抽象数据类型

  串与线性表的区别:线性表注重单个元素的操作,比如查找,删除一个元素;串注重查找子串位置,得到指定位置子串,替换子串等操作。

	ADT 串(string)
	Data
	  串中元素仅有一个字符组成,相邻元素具有前驱和后继关系。
	Operation
	  StrAssign(T,*chars):生成一个其值等于字符串常量chars的串T。
	  StrCopy(T,S):串S存在,由串S复制得串T。
	  ClearString(S):串S存在,将串复制得串T。
	  StringEmpty(S):若串S为空,返回true,否则返回false。
	  StrLength(S):返回串S的元素个数,即串的长度。
	  StrCompare(S,T):若S>T,返回值>0,若S=T,返回0,若S<T,返回值<0。
	  Concat(T,S1,S2):用T返回由S1和S2联接成的新串。
	  SubString(Sub,S,pos,len):串S存在,1<=pos<=StrLength(S),且0<=len<=StrLength(S)-pos+1,用Sub返回串S的第pos个字符起长度为len的子串。
	  Index(S,T,pos):串S和T存在,T是非空串,1<=pos<=StrLength(S),若主串S中存在和串T值相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置,否则返回0.
	  Replace(S,T,V):串S、T和V存在,T是非空串。用V替换主串S中出现的所有与T相等的不重叠的子串。
	  StrInsert(S,pos,T):串S和T存在,1<=pos<=StrLength(S)+1,在串S的第pos个字符之前插入串T。
	  StrDelete(S,pos,len):串S存在,1<=pos<=STrLength(S)-len+1,从串S中删除第pos个字符起长度为len的子串。
	endADT
  Index的实现算法:

		/*T为非空串,若主串S中第pos个字符之后存在与T相等的子串*/
		/*则返回第一个这样的子串在S中的位置,否则返回0*/
		int Index(String S,String T,int pos)
		{
			int n,m,i;
			String sub;
			if(pos > 0)
\			{
				n = Strlength(S);   /*得到主串S的长度*/
				m = Strlength(T);  /*得到子串T的长度*/
				i = pos;
				while(i <= n - m + 1)
				{
					SubString(sub,S,i,m); /*取主串第i个位置*/
								/*长度与T相等子串给sub*/
					if(StrCompare(sub,T) != 0)   /*如果两串不相等*/
						++i;
					else                /*如果两串相等*/
						return i;        /*则返回i值*/
				}
			}
			return 0;   /*若无子串与T相等,返回0*/
		}
4、串的存储结构:

  串的顺序存储结构:用一组地址连续的存储单元来存储串中的字符序列,按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,一般使用定长数组来定义。一般数组的第一个元素存储串的长度值。

    存在的问题:两串的联接Conact,新串的插入StrInsert以及字符串的替换Replace都有可能使得串序列的长度超过数组的长度MAXSIZE,出现上溢。因此串值的存储空间可在程序执行过程中动态分配。如:利用计算机的自由存储区堆,堆可以利用分配函数malloc()和free()来管理。

  串的链式存储结构:一个结点可以存放一个字符,也可以存放多个字符,最后一个结点若是未被占满时,可以用#或其他非串值字符补全。

    一个结点存放了多少个字符,会直接影响着串处理的效率。

    串的链式存储结构的优势:连接串和串时比较方便,缺点:不如顺序存储灵活,性能不如顺序存储结构好。

5、朴素的模式匹配算法

  串的匹配算法:子串的定位操作

  用基本的数组实现代码:

		/*返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0*/
		/*T非空,1<=pos<=StrLength(S)*/
		int Index(String S,String T,int pos)
		{
			int i = pos;  /*i用于主串S中当前位置下标,若pos不为1*/
			int j = 1;   /*j用于子串T中当前位置下标值*/
			while(i <= S[0] && j >= T[0])  /*若i小于S的长度且j小于T的长度时循环*/
			{
				if(S[i] == T[j])   /*两字母相等则继续*/
				{
					++i;
					++j;
				}
				else            /*指针后退重新开始匹配*/
				{
					i = i - j + 2; /*i退回到上次匹配首位的下一位*/
					j = 1;
				}
			}
			if(j > T[0])
				return i - T[0];
			else
				return 0;
		}

  最好的情况,时间复杂度:O[1],平均查找(n+m)/2,n为主串的长度,m为子串的长度,时间复杂度为O[n+m]。

  最坏的情况,时间复杂度O[(n-m+1)*m]。

6、KMP模式匹配算法

  模式串T各个位置的j值的变化定义为一个数组next,next的长度就是T的长度。

next[j]= 0,当j=1时

Max{k|1,1<k<j,前缀同的个数加1}

1,其他情况

  KMP模式匹配算法实现

		/*通过计算返回子串T的next数组*/
		void get_next(String T,int *next)
		{
			int i,j;
			i = 1;
			j = 0;
			next[1] = 0;
			while(i < T[0])    /*此处T[0]表示串T的长度*/
			{
				if(j == 0 || T[i] == T[j]) /*T[i]表示后缀的单个字符*/
							  /*T[j]表示前缀的单个字符*/
{
					++i;
					++j;
					next[i] = j;
				}
				else
				{
					j = next[j];   /*若字符不相同,则j值回溯*/
				}
			}
		}

		/*返回子串T在主串S中第pos个字符之后的位置。若不存在,则函数返回值为0。*/
		/*T非空,1<=pos<=STrLength(S)*/
		int Index_KMP(String S,String T,int pos)
		{
			int i = pos; /*i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配*/
			int j = 1;  /*就用于子串T中当前位置下标值*/
			int next[255]; /*定义一个next数组*/
			get_next(T,next); /*对串T作分析,得到next数组*/
			while(i <= S[0] && j <= T[0])  /*若i小于S的长度且j小于T的长度时,循环继续*/
			{
				if(j == 0 || S[i] == T[j]) /*两字母相等则继续*/
							  /*相对于朴素算法增加了j=0判断*/
				{
					++i;
					++j;
				}
				else       /*指针后退重新开始匹配*/
				{
					j = next[j];   /*j退回合适的位置,i值不变*/
				}
			}
			if(j > T[0])
			{
				return i - T[0];
			}
			else
			{
				return 0;
			}
		}
  KMP模式匹配算法改进

		/*求模式串T的next函数修正值并存入数组nextval*/
		void get_nextval(String T,int *nextval)
		{
			int i,j;
			i = 1;
			j = 0;
			nextval[1] = 0;
			while(i < T[0])   /*此处T[0]表示串T的长度*/
			{
				if(j == 0 || T[i] == T[j])   /*T[i]表示后缀的单个字符*/
							    /*T[j]表示前缀的单个字符*/
				{
					++i;
					++j;
					if(T[i] != T[j])  /*若当前字符与前缀字符不同*/
					{
						nextval[i] = j; /*则当前的j为nextval在i位置的值*/
					}
					else
					{
						nextval[i] = nextval[j];  /*如果与前缀字符相同*/
									  /*则将前缀字符的nextval赋值给nextval在i位置的值*/
					}
				}
				else
				{
					j = nextval[j];  /若字符不相同,则j值回溯/
				}
			}
		}
  nextval数组值推导

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值