数据结构学习笔记——串



串的基本概念
    串(或字符串),是由零个或多个字符组成的有穷序列。含零个字符的串称为空串,用Ф表示。
    串中所含字符的个数称为该串的长度(或串长)。
    当且仅当两个串的长度相等并且各个对应位置上的字符都相同时,这两个串才是相等的。
    一个串中任意个连续字符组成的子序列(含空串,但不含串本身)称为该串的子串。例如,“a”、“ab”、“abc”和“abcd”等都是“abcde”的子串(平凡子串不包括自身)。

问题: “abcde”有多少个平凡子串?
解:    空串数:1
    含1个字符的子串数:5
    含2个字符的子串数:4
    含3个字符的子串数:3
    含4个字符的子串数:2
共有1+2+3+4+5=15个子串。


串的存储结构

串的顺序存储及其基本操作实现
      串是一种特殊的线性表,在非紧缩格式中,它的每个结点仅由一个字符组成,因此存储串的方法也就是存储线性表的一般方法。存储串最常用的方式是采用顺序存储,即把串的字符顺序地存储在内存一片相邻的空间,这称为顺序串。

串的非紧缩格式(一个单元存放一个字符)与串的紧缩格式(一个单元存放多个字符) ... ...

顺序存储采用一般顺序表的存储结构,其类型定义如下:
#define MaxSize 100
typedef 
struct
{
  
char data[MaxSize];
  
int len;
} strtype;
//[紧缩格式]
     其中,ch域用来存储字符串,len域用来存储字符串的当前长度,MaxSize常量表示允许所存储字符串的最大长度。在C语言中每个字符串以'\0'标志结束(在这个结构体中不需要用'\0'标志结束,以下标为0开始存入字符)。

ASCII比较字符串
  由于 "大写字母<小写字母" ,并且a<b,因此在比较时ASCII大的字母比较靠前,但要特殊考虑大小写夹杂的情况

串的链式结构存储
    链式方式存储串,即用单链表形式存储串。这称为链式串或链串。
链串中的结点类型定义:
typedef struct snode
{    
char data;
     
struct snode *next;
} LiString;

例:在链串中,设计一个算法把最先出现的子串"ab"改为"xyz"。    
解:在串s中找到最先出现的子串"ab",p指向data域值为'a'的结点,其后为data域值为'b'的结点。将它们的data域值分别改为'x'和'z',再创建一个data域值为'y'的结点,将其插入到*p之后。本例算法如下:
void Repl(LiString *&s)
{    
    iString 
*p=s->next,*q;int find=0;
    
while (p->next!=NULL && find==0)
    {     
        
if (p->data==‘a’ && p->next->data==‘b’)  /*找到*/    
        {   p
->data='x';p->next->data='z';        
               
/*替换为xyz*/
                q
=(lstring *)malloc(sizeof(lstring));
                q
->data='y';q->next=p->next;
                p
->next=q;
                find
=1;
               }
               
else p=p->next;
        }
}
扩展,编写一个算法实现替换字符串(提示:查找(串的模式匹配,见下面的介绍)、替换相结合)
--------------------------------------------------------

重点:
串的模式匹配————(本人认为较难,很难很难,不过绝对值得一学,学会了有成就感
    设有主串s和子串t,子串t的定位就是要在主串s中找到一个与子串t相等的子串。通常把主串s称为目标串,把子串t称为模式串,因此定位也称作模式匹配。模式匹配成功是指在目标串s中找到一个模式串t;不成功则指目标串s中不存在模式串t。

算法一:BF算法(Brute-Force)
    Brute-Force简称为BF算法,亦称简单匹配算法,其基本思路是:
    从目标串s="s0s1…sn-1"的第一个字符开始和模式串t="t0t1…tm-1"中的第一个字符比较,若相等,则继续逐个比较后续字符;否则从目标串s的第二个字符开始重新与模式串t的第一个字符进行比较。依次类推,若从模式串s的第i个字符开始,每个字符依次和目标串t中的对应字符相等,则匹配成功,该算法返回i;否则,匹配失败,函数返回-1。

一种实现:
int indexpos(SqString str,SqString substr)
{    
int i,j,k,idx=-1;
    
for (i=0;i<str.len;i++)
    {  
        
for (j=i,k=0;str.data[j]==substr.data[k];j++,k++);
         
if (k==substr.len) //注意j每次从i开始,有回溯
                  return(i);
    }
    
return(-1);
}

二种实现:
int index(SqString s,SqString t)
{  
    
int i=0,j=0,k;
    
while (i<s.len && j<t.len)
    {    
if (s.data[i]==t.data[j])      /*继续匹配下一个字符*/
    {     i
++; j++;  }   /*主串和子串依次匹配下一个字符*/
    
else     /*主串、子串指针回溯重新开始下一次匹配*/
    {     
                  i
=i-j+1;     /*主串从下一个位置开始匹配*/
                  j
=0;            /*子串从头开始匹配*/
            }
     }
     
if (j>=t.len)   k=i-t.len;     /*返回匹配的第一个字符的下标*/
     
else  k=-1;                /*模式匹配不成功*/
     
return k;
  }

上面这两个算法都不怎么难理解~~
关键是下面这个KMP模式匹配算法:

算法二:
如今呢我也是,似懂非懂,半懂加不懂~~~
当然里面最重要的一步就是求next数组~~~
next数组的功能是,字符串在匹配失效时,主串不用再向前做回溯操作即没有 i=i-j+1; 这步
而只对模式串做右滑操作,到底右滑多少,由next对应模式失配的下标决定。
而相应next数组的产生只取决模式自身,其证明亦很简单
关键是如何得到next数组。。。。。(这个问题以后会详细说明,现在先暂且搁置先赶进度去,以后有时间再写一个好的)
----------------------------------------------------------------------------------------------------------------------------------------------
练习:
      一个文本串可用事先给定的字母映射表进行加密。例如,设字母映射表为:
     a b c d e f g  h  i  j  k l m n o p q  r s  t  u v w x y z
     n g z q t c o b m u h e l   k p d a w x  f  y  i  v r  s j
     则字符串“encrypt”被加密为"tkzwsdf"。试写一个算法将输入的文本进行加密后输出;另写一个算法将输入的已加密文本串进行解密后输出。
原文地址:https://www.cnblogs.com/_programmer/p/1570142.html