• 数据结构-串


     

     

    一、 串类型的定义

    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语言中字符串中隐藏一个特殊的字符即’’,它的作用是标识字符串结束,因此称’’为字符串结束符。

    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];     //最后以’’结束标识字符串结束

    当如此顶以后串的各种操作就可以实现了,有一些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	",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();
    }
  • 相关阅读:
    1.7 All components require plug-in?
    1.6 Why only in China?
    1.5 A better alternative thing: React Native
    1.4 The usage of plug-in
    1.3 History of Android Plug-in Programing
    SQL Server 查询请求
    matplotlib 绘图的核心原理
    数据加密 第六篇:透明文件加密
    数据加密 第五篇:非对称密钥
    SSIS 数据类型 第二篇:变量的数据类型
  • 原文地址:https://www.cnblogs.com/TimVerion/p/11194268.html
Copyright © 2020-2023  润新知