您的位置:首页 > 理论基础 > 数据结构算法

重读数据结构之-- 字符串

2013-12-06 23:42 190 查看
六 字符串

1.定义 由零个或多个字符组成的有限序列,又名字符串。

2.特性 空格串是有长度的。子串:串中任意个数的连续字符组成的子序列。串的比较是通过组成串的字符之间的编码来进行的。字符的编码就是字符在其对应字符集中的序号。比如a<b

3.ASCII编码 8位二进制数表示一个字符,一共可以表示256个字符。

4.Unicode编码 用16位二进制来表示一个字符,前256个字符和ASCII码表里完全相同。一共可以表示约65万个字符。

5.串的比较

① 相等:c语言中两个串相等必须是长度和各个位置对应的字符都相等才行。

② 两串长度不同,但对应位置字符都相同,则短串小于长串;对应位置第一个不相同的字符,决定两串大小。

6.串与线性表 串的基本操作完全不同于线性表,串更多的是对字串位置的查找,得到指定位置字串,替换字串等。

7.串的基本操作 :生成串;复制串;清空串;判断串是否为空;返回串长度;串大小比较;串的连接;返回指定位置间的字串;判断串中是否有指定的字串;字串的替换;插入串;删除串。

8.串的存储结构

①顺序结构

1.顺序结构就决定了串有一个固定大小的存储区,需要预定义一个最大串长度,一般将实际有效长度保存在数组的0下标位置,也有语言不存,只是在最后加一个“\0”结束标记。

2.为适应串长度的经常变化,串的顺序存储空间可以动态分配,也就是堆的概念。堆是指计算机中的一个自由存储区,适合存放常量值,堆可由c语言的malloc和free来管理。

②链式存储结构

1.链的结点如果只存一个字符是巨大浪费,因此链串的结点可以存放多个字符,比如统一规定每个结点都放4个,那么最后一个结点如果没填满,则用其他非字符符号补全。

9.朴素的模式匹配算法

①概念 字串的定位操作称为:串的模式匹配

②原理 对主串的每一个字符作为字串开头,与要匹配的字符串进行匹配。即:外循环是针对主串每一个字符遍历,内循环是针对主串做长度为T的小循环。

③纯数组实现朴素串模式匹配:

④缺点:对于每次都是直到遍历至被匹配字符串最后一个字符,才发现它和主串上不一样,以至于全部撤回原位置,这种算法就会显的低效。

//临时定义字符串结构体
typedef struct String{
char data[MAXSIZE];
}String,*Str;

//朴素的模式匹配算法
//返回字串T在主串S中第pos个字符之后的位置。若不存在,则函数返回0
int Index(String S,String T,int pos){
int i=pos;//记录S中当前位置下标,若pos不为1,则从pos位置开始匹配,pos就是主串的循环起始位置
int j=1; //j用于字串T中当前位置下标值
while(i<=S.data[0] && j<=T.data[0]){
if(S.data[i]==T.data[j]){
++i;
++j;
}else{
i=i-j+2;//之前匹配全部作废,i回退到最开始匹配成功位置的下一位,成功匹配的个数=j-1;所以原来位置下一个=i-(j-1)+1
j=1;//归位重新开始
}
if(j>T.data[0]){//T串都遍历完了,j累加完整,即全部长度都匹配了,表示成功找到
return i-T.data[0];//当前i回退到最开始匹配上的地方,返回这个值
}else{
return 0;//没有一次匹配成功的,即没找到
}
}
}

10.KMP模式匹配算法--高效匹配:好马不吃回头草

①原理:主串的位置i不回溯,子串的位置j选择性回溯,j回溯到的点取决于当前字符之前的串的前后缀的相似度。

创建针对j值的数组next,记录j下一次应该所在的位置,next数组长度就是字串长度

②next数组的推导

1. j=1时,即当前匹配是T串第一个位置字符时,规定next[1]=0。

2.如果当前字符之前的字符串中,没有后缀能与前缀匹配,那么规定next[j]=1.

3.如果有前后缀匹配上了,则当前next[j]值从1开始累加,相同的匹配情景其next数组值也相同。

4.前后缀的意思是,前缀必须包含第1个字符,后缀必须包含当前字符之前的串的最后一个字符。

③next数组代码实现

//KMP匹配算法
//记录匹配字符串的字符跳转位置值的next数组的生成算法
void get_next(String T,int *next)
{
int i=1;
int j=0;
next[1]=0;//第一个字符j值规定为0
while(i<T.data[0]){  //遍历匹配字符串
if(j==0 || T.data[i]==T.data[j]){//如果后缀字符T.data[i] 匹配上了 前缀字符T.data[j]
++i;//匹配成功后继续下一个位置的匹配,后缀i移到下一个
++j;//下一个位置前缀j从下一个开始,匹配成功的前一个略过 ,由于j初始为0,所以第一次循环j已经是1
next[i]=j;//当前位置的跳转值就是j值
}  else{//匹配失败,前后缀没有相同的
j=next[j];//j值的回溯,回到上一次j的跳转值
}
}
}

//KMP匹配算法,和朴素匹配唯一不同在于对匹配失败后j值的跳转做精细精准化处理
int Index_KMP(String S,String T,int pos){
int i=pos;
int j=1;
int next[255];
get_next(T,next);
while(i<=S.data[0] && j<=T.data[0]){
if(j==0 || S.data[i]==T.data[j]){
++i;
++j;
}else{
j=next[j];//匹配失败跳转到数组指定位置
}
}
if(j > T.data[0])
return i-T.data[0];
else
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: