学习 严蔚敏讲数据结构笔记09

1.2  串的表示和实现

如果在程序设计语言中,串只是作为输入或输出的常量出现,则只需存储此串的串值,即字符序列即可。但在多数非数值处理的程序中,串也以变量的形式出现。

 

一、串的定长顺序存储表示

二、串的堆分配存储表示

三、串的块链存储表示

 

 

一、串的定长顺序存储表示

#define MAXSTRLEN 255 //用户可在255以内定义最大串长

typedef unsigned char Sstring[MAXSTRLEN+1];//0号单元存放串的长度

串的实际长度可在这个预定义长度的范围内随意设定,超过预定义长度的串值则被舍去,称之为“截断”。

 

例如:串的联接算法中需要三种情况处理:

10_002

Status Concat(SString S1, SString S2,  SString &T)

{

         //T返回由S1S2联接而成的串,若未截断,则返回True,否则返回False

         if(S1[0]  + S2[0] <= MAXSTRLEN)

         {

                   //未截断

                   T[1..S1[0]]  = S1[1..S1[0]];

                   T[S1[0]+1..S1[0]+S1[0]]  = S2[1..S2[0]];

                   T[0]  = S1[0]+S2[0];

                   uncut  = TRUE;

         }

         else  if(S1[0] < MAXSTRLEN)

         {

                   //截断

                   T[1..S1[0]]  = S1[1..S1[0]];

                   T[S1[0]+1..MAXSTRLEN]  = S2[1..MAXSTRLEN-S1[0]];

                   T[0]  = MAXSTRLEN;

                   uncut  = FALSE;

         }

         else

         {

                   //截断(仅取S1)

                   T[0..MAXSTRLEN]  = S1[0..MAXSTRLEN];

                   //T[0]  == S1[0] == MAXSTRLEN

                   uncut  = FALSE;

         }

         return  uncut;

}

按这种串的表示方法实现的串的运算时,其基本操作为“字符序列的复制”。

 

二、串的堆分配存储表示

typedef struct

{

char *ch; //若是非空串,则按照串长分配存储区,否则chNULL

int length; //串长度

} HString;

通常,C语言中提供的串类型就是以这种存储方式实现的。系统利用函数malloc()free()进行串值空间的动态管理,为每一个新产生的串分配一个存储区,称串值共享的存储空间为“堆”C语言中的串以一个空字符为结束符,串长是一个隐含值。

这类串操作的实现算法为:先为新生成的串分配一个存储空间,然后进行串值的复制。

 

三、串的块链存储表示

11_001

#define CHUNKSIZE 80 //可由用户定义块大小

typedef struct Chunk

{

         //结点机构体

         char  ch[CHUNKSIZE];

         struct  Chunk *next;

}Chunk;

typedef struct

{

         //传递链表结构

         Chunk  *head, *tail; //串的头和尾指针

         int  curlen; //串的当前长度

}LString;

数据域为字符占1字节,指针域为4字节。存储结构的存储密度为1/5

串值也可用链表来存储,由于串的数据元素是一个字符,它只有8位二进制数,因此用链表存储时,通常一个结点中存放的不是一个字符,而是一个子串,例如:在编辑器系统中,整个文本编辑区可以看成是一个串,每一行是一个子串,构成一个结点。即:同一行的串定长结构(80个字符),行和行之间用指针相联接。

 

4.3串的模式匹配算法

这是串的一种重要操作,很多软件,若有“编辑”菜单选项的话,则其中必有“查找”子菜单项。

首先,回忆一下串匹配(查找)的定义:

INDEX(S,T,pos)

初始条件:串ST存在,T是非空串,1<=pos<=StrLength(S)

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

下面讨论以定长顺序结构表示串时的几种算法。这里有三种算法:

1.      简单算法

2.      首尾匹配算法

3.      KMP(D.E.Knuth,V.R.Pratt,J.H.Morris)算法

 

1.      简单算法

11_002

int Index(SString S, SString T, int pos)

{

         //返回子串T在主串S中第pos个字符之后的位置,若不存在,则函数值为0

         //其中,T为非空,1<=pos<=StrLength(S).

         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(i  > T[0])

                            return  i - T[0];

                   else

                            return  0;

         }

}

 

二、首尾匹配算法

先比较模式串的第一个字符,在比较模式串中的最后一个字符,最后比较模式串中从第二个到第n-1个字符。

11_003

int Index_FL(SString S, SString T, int  pos)

{

         sLength  = S[0];

         tLength  = T[0];

         i  = pos;

         patStartChar  = T[1];

         patEndChar  = T[tLength];

         while(i  <= sLength - tLength + 1)

         {

                   if(S[i]  != patStartChar)

                   {

                            ++  i; //重新匹配起始点

                   }

                   else 

                            if(S[i  + tLength - 1] != patEndChar)

                            {

                                     ++  i;

                            }

                   else

                   {

                            //检查中同字符的匹配情况

                            //...

                            k  = 1;

                            j  = 2;

                            while(j  < tLength && S[i+k] == T[j])

                            {

                                     ++  k;

                                     ++  j;

                            }

                            if(j  == tLength)

                            {

                                     return  i;

                            }

                            else

                            {

                                     return  ++ i; //重新开始下一次的匹配检测

                            }

                   }

         }

         return  0;

}

 

四、KMPD.E.Knuth,V.R.Pratt, J.H.Morris)算法

KMP算法的时间复杂度可以达到O(m+n)

S[i]<>T[j]时,

已经得到的结果:S[i-j+1…i-1] == T[1…j-1]

若已知 T[1…k-1] == T[j-k+1 … j-1]

则有 S[i-k+1…i-1] == T[1…k-1]

定义模式串next函数

 

 

 

12_001

int Index_KMP(SString S, SString T, int  pos)

{

         //1  <= pos <= StrLength(S)

         i  = pos;

         j  = 1;

         while(i  <= S[0] && j <= T[0])

         {

                   if(j == 0 || S[i] == T[j])

                   {

                            ++  i;

                            ++  j;

                   }

                   //继续比较后继字符

                   else

                   {

                            j  = next[j]; //模式串向右移动

                   }

         }

         if(j  > T[0])

         {

                   return  i - T[0]; //匹配成功

         }

         else

         {

                   return  0;

         }

}//Index_KMP

next函数值的过程是一个递推过程,分析如下:

已知:next[1]=0;

假设:next[j]=k;T[j]=T[k];next[j+1]=k+1;

若:T[j] <> T[k] 则需往前回朔,检查T[j]==T[?]

这实际上也是一个匹配的过程,不同在于:主串和模式串是一同一个串。

 

10_002

void get_next(SString &T, int  &next[])

{

         //求模式串Tnext函数值并存入数组next

         i  = 1;

         next[1]  = 0;

         j  = 0;

         while(i  < T[0])

         {

                   if(j  == 0 || T[i] == T[j])

                   {

                            ++  i;

                            ++  j;

                            next[i]  = j;

                   }

                   else

                   {

                            j  = next[j];

                   }

         }

}//get_next

还有一种特殊情况需要考虑:

例如:S=’aaabaaabaaabaaabaaab’

T=’aaaab’

Next[j]=01234

Nextval[j]=00004

 

12_003

void get_nextval(SString &T, int  &nextval[])

{

         i  = 1;

         nextval[1]  = 0;

         j  = 0;

         while(i  < T[0])

         {

                   ++  i;

                   ++  j;

                   if(T[i]  != T[j])

                   {

                            next[i]  = j;

            //少一行语句

                   }

                   else

                   {

                            j  = nextval[j];

                   }

         }

}//get_nextval

1.      熟悉串的七种基本操作的定义,并能利用这些基本操作来实现串的其它各种操作方法。

2.      熟练掌握在串的定长顺序存储结构上实现串的各种操作方法。

3.      掌握串的堆存储结构以及在其上实现串的基本方法。

4.      理解串匹配的KMP算法,熟悉NEXT函数的定义,学会手工计算给定模式串的NEXT函数值和改进的NEXT函数值。

5.      了解串操作的例子

 

你可能感兴趣的:(学习 严蔚敏讲数据结构笔记09)