數據結構-串


 

 

一、 串類型的定義

  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();
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM