数据结构期末复习(4.串)

Ø 从数据结构角度看,栈和队列是 操作受限 的线性表,他们的逻辑结构相同。
Ø 串是重要的 非数值处理对象 ,它是以 字符 作为数据元素的线性表。 

4.1串类型的定义

定义,逻辑结构
定义:字符串,即以 零个或者 多个字符组成的有限序列
           是以数据元素为单个字符的特殊线性表。
串术语:

子串:串中任意个连续的字符组成的子序列。

主串:包含子串的串。

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

 4.1.1串类型的定义

插入:

删除:

串赋值:

串赋值:

串链接:

串置换:

假设 S = ²abcaabcaaabca²,  T = ²bca ²

V = ²x ², 则经置换后得到 S = ²axaxaax ²

求子串:

定位函数:


基本操作:

上述 的所有操作中,串赋值StrAssign,串比较StrCompare,求串长StrLength,串链接Concat,

以及求最小子串SubString

思考StrDelete (&S, pos, len)  (删除)怎么用上面的操作实现?

设目标串的长度为length:

则有:

void StrDelete(&S,pos,len){
    length=Strlength(S);
    Concat(&T,SubString(&S,1,pos-1),SubString(&S,pos+len,length-(pos+len-1)));
    StrAssign(&S,&T);
}

串和对应线性表的比较:

    串的逻辑结构约束和线性表即为相似,区别仅仅在于串的数据对象约束为字符集

    线性表的基本操作中,大多以“单个元素”作为操作对象;

    而在的基本操作中,通常以“串的整体”作为操作对象。

答:Strlength(s) = 14;

SubString(s,8,7)=STUDENT;

SubString(t,2,1)="O";

Index(s,'A')=3;

Index(s,t,3)=0;(s中没有t);

Replace(s,'STUDENT',q)=I AM A WORKER’;


        4.2串类型的表示和实现

存储规则,运算规则
串有三种机内表示方式:
1.定长顺序存储方式:
用一组地址连续的存储单元存储串的字符序列。
2.堆分配存储表示:
用一组地址连续的存储单元存储串值的字符序列 , 但存储空间是在程序执行过程中动态分配而得。
3.串的块链存储方式:
链式方式存储。
1 2 顺序存储   3 链式存储。

4.2.1静态存储分配:

特点: 用一组连续的存储单元来存放串,直接使用定长的字符数组来定义,数组的 上界预先给出 ,故称为 静态存储分配
#define Maxstrlen 255    //用户可用的最大串长
            typedef unsigned char SString[ Maxstrlen+1 ] ;
            SString s;   //s是一个可容纳255个字符的顺序串。

一般用 SString[0] 存放串长信息;

关于串的操作中,串链接操作属于静态存储分配

4.2.2堆存储分配

讨论:想存放超长字符串怎么办?——静态数组有缺陷!

改用动态分配的一维数——“堆”!

特点:仍用一组连续的存储单元来存放串,但存储空间是在程序执行过程中动态分配而得

特点:用malloc函数,也可用relloc函数

关于串的操作中,插入操作,赋值操作属于堆分配存储操作。

4.2.3链式存储

特点:用链表存储串值,易于插入和删除。

法1的存储密度为:1\2                                        法二存储密度为:9\15=3\5 

 显然若数据元素更多时,法二(块链结构)更优。

块链的定义:

#define  CHUNKSIZE  80     //可由用户定义的块大小
typedef  struct  Chunk {           //首先定义结点类型
           char    ch [ CHUNKSIZE ];  //结点中的数据域
           struct  Chunk * next ;          //结点中的指针域
}Chunk;     

                           
typedef  struct {                 //其次定义用链式存储的串类型
            Chunk  *head;           //头指针
            Chunk  *tail;             //尾指针
            int  curLen;               //结点个数
   } Lstring;        

链式存储结构对某些操作比较方便,但是总体来说没有前面的两种存储结构灵活。


4.3串的匹配模式算法

模式匹配:即子串定位运算  index函数

算法目的:确定主串中所含子串第一次出现的位置

初始条件:1.串s(主串)2. 和 串T(模式串)存在  T是非空串  3. 1≤pos≤StrLength(s)

操作结果:若主串S中存在和串T值相同的子串,则返回它在主串S中第pos个字符之后第一次出现的位置;否则函数值为0

算法种类:1.BF算法   2.KMP算法

4.3.1BF算法

BF算法设计思想:

① BF算法设计思想:

将主串的第 pos 个字符和模式的第 1 个字符比较,

    若相等,继续逐个比较后续字符;

    若不等,从主串的下一字符pos+1起,重新与第一个字符比较。 

直到主串的一个连续子串字符序列与模式相等 。返回值为S中与T匹配的子序列第一个字符的序        号,即匹配成功。

    否则,匹配失败,返回值 0 .

BF算法的代码:

Int Index (SString S, SString T, int pos) {
  i=pos;      j=1;
  while ( i<=S[0] && j<=T[0] ) {
      if (S[i] = = T[j] ) {++i, ++j}   //继续比较后续字符
     else {i=i-j+2; j=1;}      //指针回溯到 下一首位,重新开始匹配
	}
  if(j>T[0]) return i-T[0];  //子串结束,说明匹配成功
  else return 0;
}//Index

S[0],T[0] 是储存字符串长度信息的。

思考:

1i<=S[0]可以改成S[0]-T[0]+1吗?

2)循环执行的次数最多是多少?

n为主串长度,m为子串长度,则串的BF匹配算法最坏的情况下需要比较字符的总次数为O(n*m)

4.3.2KMP算法

① KMP算法设计思想

能否利用模式串和主串部分匹配的结果加速模式串的滑动速度?要滑动到哪里?

能并且主串S的指针不必回溯,时间复杂度可以从O(n*m)提速到O(n+m)

② KMP算法的推导过程

抓住部分匹配结果的两个特征:

        设目前应与T的第k字符开始比较

        Tk-11位=Si-1i-(k-1)

即:S中位置i前面的k-1字符串=T中的前k-1

        刚才是在Si处和T的第j字符 处失配

        则Si-1i-(k-1)位=Tj-1j-(k-1)

即:S中位置i前面的k-1字符串=Tj前面的k-1

两式联立可得:T1…Tk-1’=‘Tj-(k-1) …Tj-1

意为:这一次新配对位K的前K-1位和上一次失配处的前k-1位是相同的。

           

注意:j为已知此处的失配位置,我们的目标是计算新的起点k(即该失配处j下一次应该和)。

          只剩一个未知数k,理论上已可解,且k仅仅和模式串k有关。

所以根据模式串的规律:

T1…Tk-1’=‘Tj-(k-1) …Tj-1

和已知的当前失配位置j ,可以归纳出计算新起点 k的表达式。

令k = next[ j ],则

 

为什么j=1时  next[j]=0 ?

j=1,意思就是第一个字符就匹配失败,下一趟的比较应该让i++j变成1,为了下一趟是i++j++同时增加,需要在上一趟时把j=0,然后j++后就会变成1,这时候i也增加了1.


怎样计算模式T所有可能的失配点 j 所对应的 next[j]

j=1, next[ j ]≡ 0因为属于“j=1”;

j=2, next[ j ]≡ 1因为属于“其他情况”

j=3, k={2},只需查看‘T1 ‘T2

j=4, k={23},要查看‘T1’=‘T3和‘T1T2’‘ T2 T3

j=5, k={234},要查看‘T1’=‘T4、‘T1T2‘T3T4

                                                  ‘T1T2T3’‘ T2T3T4

所谓的max值的是k可以取得集合中满足匹配条件的k值的极大值。


求解Next的方法:

根据定义的公式的方法:用前缀和后缀的方法,非常简单。

(1) next[1]=0,next[2]=1; 

(2)求后面的next[j]时,把第1位到第j-1位的字符串取出来,求该串的前缀和后缀,前缀后缀最长是j-2,取出最长的相等的前缀和后缀,这个长度加一就是next[j]

例如:a  b  a  a  b  c  a  c

next[4]=?  前面的串是:aba,前缀和后缀a=a,长度是1,所以next[4]=1+1=2  (最大长度加1

next[6]=?  前面的串是:abaab,前缀和后缀ab=ab,长度是2,所以next[6]=2+1=3(最大长度加1

实用方法。


nextval序列的写法:

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值