数据结构-串

 

 

一、 串类型的定义

  1. 1.        串的定义

串(string)(或字符串)是由零个或多个字符组成的有序序列,一般记为

              S=”a1a2an”   (n>=0)

其中,s是串的名,用双引号括起来的字符序列是串的值;ai (1≤i≤n)可以是字母、数字或其他字符;串中字符的数目n成为串的长度。零个字符的串称为空串(null string),它的长度为0。

串中任意个连续的字符组成的子序列称为该串的子串。包含子串的串相应的称为主串。通常称字符在序列中的序号为该字符在串中的位置。子串在主串中的位置则以子串的第一个字符在主串中的位置来表示。

例如,假设有a、b、c、d四个字符串:

           a=”BEI”        b=”JING”

           c=”BEIJING”    d=”BEI JING”

则它们的长度分别为3、4、7、8;并且a、b都是c、d的子串,a在c和d中的位置都是0,而b在c中的位置是3,在d中的位置是4;可见字符串的索引是从0开始的

称两个串相等的,当且仅当这两个串的值相等。也就是说,只有当两个字符串的长度相等,并且各个对应位置的字符都相等才相等。例如上例子中a、b、c、d都互不相等。

值得一提的是,串值必须用一对双引号括起来,但双引号本身不属于串,它的作用只是为了避免与变量名或数的常量混淆而已。另在高级语言中,如C语言中字符串中隐藏一个特殊的字符即’\0’,它的作用是标识字符串结束,因此称’\0’为字符串结束符。

  1. 2.        串的操作

字符串可以有丰富的操作,在日常非数值运算大量的都是字符串的操作。归纳总结可以大致分为以下操作

(1)赋值           strcpy(数组名、字符串);

(2)判空           strlen()    strcmp()   

(3)字符串比较     strcmp

(4)求字符串长度   strlen

(5)字符串拷贝     strcpy

(6)字符串连接     strcat

(7)求字符串子串(截取字符串) 

二、 串类型的表示和实现

  1. 1.   串的表示

(1)定长顺序存储表示:类似线性表的顺序存储结构,用一组地址连续的存储单元存储字符串的字符序列。

(2)堆分配存储表示:这种存储方式特点是:仍一一组连续的存储单元存放字符串序列,但它们的存储空间是在程序执行过程中动态分配而得的。

(3)块链存储表示:和线性表的链式存储类似,也是用链表来保存字符串的值。根据串的特殊,若每个字符占一个结点太小,则采取每个结点可以存放一个也可以存放多个字符。如图所示:图a就是块链存储方式,而图b则过于浪费空间。

  1. 1.   串的实现

 

首先串的存储方式不同其实现方式就是不一样的,这里我们采用第一种存储方式即定长顺序存储表示。

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

typedef unsigned char SString[MAX+1];     //最后以’\0’结束标识字符串结束

当如此顶以后串的各种操作就可以实现了,有一些C语言中自带的系统可完成一部分,如字符串拷贝strcpy,字符串连接strcat,字符串比较strcmp,求字符串长度strlen。也有另外一部分需要自己实现,比如截取字符串substring:

char * substring(char sub[],char s[],int pos,int len)

{

       int i,count;

       if(pos<0 ||pos>strlen(s)-1||len<0||len>strlen(s)-pos)  //判断pos(开始截取位置)是否合法

       {                                          //判断len(截取长度)是否合法

          printf("输入参数有误");

              return "error";

       }

       else

       {

           count=0;

           for(i=pos;i<pos+len;i++)      //截取字符串

              {

                sub[count]=s[i];

                count++;

              }

              return sub;

       }

}

void main()

{

       char s[100]="I love BAWEI University";

       char sub[20];

       printf("%s",substring(sub,s,2,4));

}

 

运行效果如图所示:

 

一、 串的模式匹配算法

    子串的定位操作通常称为串的模式匹配,是各种串处理系统中最重要的操作之一。

  1. 1.   ACM算法:子串的定位函数Index(S,T,pos)
int index(char s[],char t[],int pos)//返回子串t在主串s中的位置,pos指定的是在主串的第pos开始出现子串的位置,若全串查找pos设置为0

{                                    

    int i,j;

    i=pos;

    j=0;

    while(i<strlen(s)&&j<strlen(t))

    {

        if(s[i]==t[j])

        {

            i++;

            j++;        //继续比较后面的字符

        }

        else

        {

            i=i-j+1;     //i后退重新开始匹配

            j=0;

        }

    }

    if(j==strlen(t))

    {

         return i-strlen(t);

    }

    else

    {

        return -1;  //没有匹配到

    }

}

void main()

{

    char s[100]="ababcabcacbaab";

    char t[100]="abcac";

    int pos=0;

    printf("%d",index(s,t,pos));

}

 

运行结果是5,即在主串下标5的位置出现abcac这个子串。下面我们看下这个匹配的过程示意图:

              ↓i=2

第一趟匹配 a b a b c a b c a c b a b

           a b c

              ↑j=2

 

             ↓i=1

第二趟匹配:a b a b c a b c a c b a b

             a

             ↑j=0

                    ↓i=6   

第三趟匹配:ab a b c a b c a c b a b

               a b c a c

                     ↑j=4

 

                ↓i=3   

第四趟匹配:a b a b c a b c a c b a b

                a

                ↑j=0

 

                  ↓i=4   

第五趟匹配:a b a b c a b c a c b a b

                  a

                  ↑j=0

 

                          ↓i=10   

第六趟匹配:a b a b c a b c a c b a b

                   a b c a c

                          ↑j=5

  1. 2.   ACM算法:模式匹配的一种改进算法(KMP算法)

 

    这种改进算法是D.E.Knuth与V.R.Pratt和J.H.Morris同时发现的,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法)。此算法可以在O(n+m)的时间数量级上完成串的模式匹配操作。其改进在于:每趟匹配过程出现字符比较不等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式串向右“滑动”尽可能远的一段距离后,继续进行比较。下面先从具体例子看起。

    回顾上小节的匹配过程示例,在第三趟的匹配过程中,当i=6,j=4字符比较不等时,又从i=3,j=0重新开始比较。然后,经仔细观察可发现,在i=3和j=0,i=4和j=0,及i=5和j=0这三次比较都是不必进行的。因为从第三趟部分匹配的结果就可得出,主串中下标3、4、5的字符必然是‘b’、‘c’、‘a’(即模式串下标为1、2、3的字符)。因为模式中第一个字符是a。因此它无需再和这三个字符进行比较,而仅需将模式向右滑动3个字符的位置继续进行i=6,j=1时的字符比较即可。同理,在第一趟匹配中出现字符不等时,仅需将模式向右移动两个字符的位置继续进行i=2,j=0时的字符比较。由此,在整个匹配过程中,i指针没有回溯,如下图所示。

             ↓i=2

第一趟匹配 a b a b c a b c a c b a b

           a b c

              ↑j=2

 

              ↓i →  ↓i=6

第二趟匹配 a b a b c a b c a c b a b

              a b c a c

              ↑  → ↑j=4

 

 

                    ↓i → ↓i=10

第三趟匹配 a b a b c a  b c a c b a b

                  (a ) b c a c

                     ↑j=2→↑j=5

 

 

     现在讨论一般情况。假设主串为“s1s2。。。sn”,模式串为“p1p2。。。pm”,从上例的分析可知,为了实现改进算法,需要解决下述问题:当匹配过程中产生“失配”即(si ≠pj)时,模式串“向右滑动”可行的距离多远,换句话说,当主串下标i的字符与模式中下标j的字符失配(即比较不等)时,主串下标i的字符(i指针不回溯)应与模式中哪个字符再比较。

假设此时应与模式中下标k(k<j)的字符进行比较,则模式中前k-1字符的子串必须满足下列关系式,且不可能存在k’>k满足下列关系式

“p1p2。。。Pk-1”=“si-k+1si-k+2。。。si-1”    ①

 

而已经得到的“部分匹配”的结果是

  “pj-k+1pj-k+2。。。Pj-1”=“si-k+1si-k+2。。。si-1”  ②

由式子①和式子②可知

                    “p1p2。。。Pk-1”=“pj-k+1pj-k+2。。。Pj-1”     ③

反之,若模式串存在满足式③的两个子串,则当匹配过程中,主串中第i个字符与模式中第j个字符比较不等时,仅需要将模式串向右滑动值模式中第k个字符和主串第i个字符对齐,此时,模式中头k-1个字符的子串“p1p2。。。Pk-1”必定与主串中第i个字符之前长度k-1的子串“si-k+1si-k+2。。。si-1”相等,因此,匹配仅需从模式中第k个字符与主串的第i个字符比较起继续进行。

设next[j]=k,则next[j]表明当第j个字符与主串中相应字符失配时,在模式串需中心和主串中字符进行比较的字符位置。由此可引出模式串的next函数的定义

由此定义可推出下列模式串的next函数值:

算法如下:

int get_next(char t[],int next[])  //计算next[j]的函数

{

       int i=0,j=0;

       next[0]=0;

       while(i<strlen(t))

       {

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

              {

                     i++;

                     j++;

                     next[i]=j;

              }

              else

              {

                     j=next[j];

              }

       }

}

int index(char s[],char t[],int pos)  //子串定位函数

{

       int i,j;

       int next[256];

       get_next(t,next); 

    for(j=0;j<strlen(t);j++)

    {

          printf("%d\t",next[j]);

    }

       i=pos;

       j=0;

       while(i<strlen(s)&&j<strlen(t))

       {

              if(j==-1||s[i]==t[j])

              {

                     i++;

                     j++;

              }

              else

              {

                     j=next[j]-1;    //失配时只滑动模式串到next[j]-1的位置继续比较即可

              }

       }

       if(j>=strlen(t))

       {

               return i-strlen(t);

       }

       else

       {

              return -1;  //没有匹配到

       }

}

void main()

{

       char s[100]="ababcabcacbaab";

       char t[100]="abcac";

       int pos=0;

       printf("%d",index(s,t,pos));  //打印子串在主串的位置

}    

 

一、 串的算法时间复杂度的分析

    一般的来讲,对于字符串模式匹配算法时间复杂度是与主串的长度n和子串的长度m相关的,对于未改进的定位子串的算法:最好情况时间复杂度为O(n+m)而最坏情况则可达到O(n*m),因为其i指针是要回溯的。而对于改进的模式匹配算法KMP算法其i指针不用回溯,只移动模式串的比较位置即可。这样时间复杂度就在O(n+m)级别可完成算法。

 生日快乐代码

#include "stdio.h"
#include "stdlib.h"
#include "windows.h"
#include "mmsystem.h"
#include "time.h"
#pragma comment(lib,"Winmm.lib")
int i,j;
void gotoxy(int x,int y){
    COORD c;
    c.X=x;
    c.Y=y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
int color(int c){
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c);
    return 0;
    }
void xin(){
     color(12);
   gotoxy(18,8);
   printf("");//8行28列
   Sleep(500);
   gotoxy(16,7);
   printf("");
    Sleep(500);
   gotoxy(14,6);
   printf("");
    Sleep(500);
   gotoxy(12,6);
   printf("");
    Sleep(500);
   gotoxy(10,7);
   printf("");
    Sleep(500);
   gotoxy(10,8);
   printf("");
    Sleep(500);
   gotoxy(10,9);
   printf("");
    Sleep(500);
   gotoxy(12,10);
   printf("");
    Sleep(500);
   gotoxy(14,11);
   printf("");
    Sleep(500);
   gotoxy(16,12);
   printf("");
    Sleep(500);
   gotoxy(18,13);
   printf("");
   Sleep(500);
   gotoxy(20,12);
   printf("");
       Sleep(500);
   gotoxy(22,11);
   printf("");
   Sleep(500);
   gotoxy(24,10);
   printf("");
   Sleep(500);
   gotoxy(26,9);
   printf("");
   Sleep(500);
   gotoxy(26,8);
   printf("");
    Sleep(500);
   gotoxy(26,7);
   printf("");
    Sleep(500);
   gotoxy(24,6);
   printf("");
    Sleep(500);
   gotoxy(22,6);
   printf("");
    Sleep(500);
   gotoxy(20,7);
   printf("");
       for(i=7;i<10;i++){
   gotoxy(12,i);
   printf("");
    }
     for(i=7;i<11;i++){
    
   gotoxy(14,i);
   printf("");
     }
      for(i=8;i<12;i++){
    
   gotoxy(16,i);
   printf("");
      }
       for(i=9;i<13;i++){     
   gotoxy(18,i);
   printf("");
       }
       for(i=7;i<10;i++){    
   gotoxy(24,i);
   printf("");
    }
     for(i=7;i<11;i++){
   gotoxy(22,i);
   printf("");
     }
      for(i=8;i<12;i++){
   gotoxy(20,i);
   printf("");
      }
}
void xinr(){
    color(4);
    for(i=10;i<50;i+=2){
    gotoxy(i,15);
    if(i%2==0){
    printf("");}
    else{
        printf("");
        }
    Sleep(100);
    }
    color(12);
     for(i=8;i<52;i+=2){
    gotoxy(i,16);
    printf("");
    Sleep(100);
     }
     color(4);//11浅蓝色
     for(i=6;i<54;i+=2){
    gotoxy(i,17);
    printf("");
    Sleep(100);
     }
     color(15);
      for(i=6;i<54;i+=2){
    gotoxy(i,18);
    printf("");
    Sleep(100);
      }
      color(5);//紫色
       for(i=6;i<54;i+=2){
        gotoxy(i,19);
            printf("");
            Sleep(100);
       }
       color(12);
        for(i=4;i<56;i+=2){
        gotoxy(i,20);
            printf("");
            Sleep(100);
        }
        //蜡烛
        color(6);
        gotoxy(14,11);
        printf("");
            Sleep(100);
            color(12);
    for(i=15;i>12;i--){
    gotoxy(14,i);
    printf("");
    Sleep(100);
    }
     for(i=15;i>12;i--){
    gotoxy(16,i);
    printf("");
    Sleep(100);
     }
      color(6);
        gotoxy(16,11);
        printf("");
            Sleep(100);
    color(6);
        gotoxy(26,11);
        printf("");
            Sleep(100);
             color(12);
            for(i=15;i>12;i--){
    gotoxy(20,i);
    printf("");
    Sleep(100);
    }
           
    for(i=15;i>11;i--){
    gotoxy(26,i);
    printf("");
    Sleep(100);
    }
    color(6);
    gotoxy(20,11);
     printf("");
    Sleep(100);
    color(6);
        gotoxy(32,11);
        printf("");
            Sleep(100);
            color(12);
     for(i=15;i>11;i--){
    gotoxy(32,i);
    printf("");
    Sleep(100);
     }
     color(6);
        gotoxy(44,11);
        printf("");
            Sleep(100);
            color(12);
      for(i=15;i>12;i--){
    gotoxy(44,i);
    printf("");
    Sleep(100);
      }
    color(6);
    gotoxy(38,11);
    printf("");
       Sleep(100);
            color(12);
    for(i=15;i>12;i--){
    gotoxy(38,i);
    printf("");
    Sleep(100);
    }
      for(i=15;i>12;i--){
    gotoxy(46,i);
    printf("");
    Sleep(100);
      }
      color(6);
    gotoxy(46,11);
    printf("");
       Sleep(100);
   }
    
void menu(){
    for(i=0;i<58;i+=2){
        gotoxy(i,1);
        color(7);//4红色5紫色7白色9蓝色10lvse
        printf("");
        gotoxy(i,26);
        printf("");
    }
    for(i=0;i<26;i++){
        gotoxy(0,i);
        printf("");
        gotoxy(56,i);
        printf("");
    }
    for(i=2;i<56;i+=2){
        for(j=2;j<26;j++){
            gotoxy(i,j);
            color(0);
            printf("");
            }
    }
}
//happy birthday
void birthday(){
    int i;
    color(6);
    //56 20 H
    for(i=22;i<25;i++){
    gotoxy(10,i);
    printf("");
    }
    gotoxy(12,23);
    printf("");
    gotoxy(14,22);
    printf("");
    for(i=23;i<25;i++){
    gotoxy(14,i);
    printf("");
    }
    Sleep(400);
        //a
    gotoxy(18,24);
    printf("");
    gotoxy(18,23);
    printf("");
    gotoxy(20,22);
    printf("");
    gotoxy(20,23);
    printf("");
    gotoxy(22,24);
    printf("");
    gotoxy(22,23);
    printf("");
    //p左边是列
    Sleep(400);
    color(2);
    gotoxy(26,22);
    printf("");
    gotoxy(26,23);
    printf("");
    gotoxy(26,24);
    printf("");
    gotoxy(28,22);
    printf("");
    gotoxy(28,23);
    printf("");
    //p
    Sleep(400);
    color(5);
        gotoxy(32,22);
    printf("");
    gotoxy(32,23);
    printf("");
    gotoxy(32,24);
    printf("");
    gotoxy(34,22);
    printf("");
    gotoxy(34,23);
    printf("");
    //y
    Sleep(400);
    color(4);
    gotoxy(38,22);
    printf("");
    gotoxy(38,23);
    printf("");
    gotoxy(40,25);
    printf("");
    gotoxy(40,23);
    printf("");
    for(i=22;i<25;i++){
    gotoxy(42,i);
    printf("");
    }
    gotoxy(42,25);
    printf("");
    Sleep(400);
    //b
    color(10);
    gotoxy(2,3);
    printf("");
    for(i=4;i<7;i++){
    gotoxy(2,i);
    printf("");
    }
    gotoxy(4,6);
    printf("");
    gotoxy(4,5);
    printf("");
    //i
    Sleep(400);
    color(4);
    gotoxy(8,3);
    printf("");
    
    gotoxy(8,5);
    printf("");
    gotoxy(8,6);
    printf("");
    //r
    Sleep(400);
    color(12);
    for(i=4;i<7;i++){
    gotoxy(12,i);
    printf("");
    }
    //gotoxy(14,5);
    //printf("■");
    gotoxy(14,4);
    printf("");
        //t
    Sleep(400);
    color(6);
    gotoxy(18,5);
    printf("");
    gotoxy(20,5);
    printf("");
    gotoxy(22,5);
    printf("");
    gotoxy(20,4);
    printf("");
    gotoxy(20,6);
    printf("");
    gotoxy(20,7);
    printf("");
    gotoxy(22,7);
    printf("");
    Sleep(400);
    //H
    color(6);
    for(i=4;i<7;i++){
    gotoxy(26,i);
    printf("");
    }
    gotoxy(28,5);
    printf("");
    gotoxy(30,5);
    printf("");
    gotoxy(30,6);
    printf("");
    Sleep(400);
    //d
    color(10);
    for(i=3;i<7;i++){
    gotoxy(36,i);
    printf("");
    }
    gotoxy(34,6);
    printf("");
    gotoxy(34,5);
    printf("");
    //a
    Sleep(400);
    color(12);
    gotoxy(42,4);
    printf("");
    gotoxy(40,6);
    printf("");
    gotoxy(40,4);
    printf("");
    gotoxy(40,5);
    printf("");
    gotoxy(42,5);
    printf("");
    gotoxy(42,6);
    printf("");
    gotoxy(44,6);
    printf("");
    //y
    Sleep(400);
    color(12);
    gotoxy(48,3);
    printf("");
    gotoxy(48,4);
    printf("");
    gotoxy(50,4);
    printf("");
    gotoxy(52,4);
    printf("");
    gotoxy(52,5);
    printf("");
    gotoxy(52,6);
    printf("");
    gotoxy(52,3);
    printf("");
    gotoxy(50,6);
    printf("");

}

void main()
{
    PlaySound(TEXT("sounds\\taiy.wav"),NULL,SND_FILENAME|SND_ASYNC|SND_LOOP);
    system ( "mode con cols=60 lines=28" );
    system("title ");
    menu();
    gotoxy(28,0);
   system("pause");
   xinr();
   birthday();
   gotoxy(10,0);
  system("pause");
  system("cls");
  xin();
}

 

posted @ 2019-07-16 13:15  Timcode  阅读(8119)  评论(0编辑  收藏  举报