C語言實現的字符串匹配(后綴數組的使用)


題目描述:妞妞有兩個字符串a和b,其中a串是一個01串,b串中除了可能有0和1,還可能有'?',b中的'?'可以確定為0或者1。尋找一個字符串t是否在字符串s中出現的過程,稱為字符串匹配。牛牛現在考慮所有可能的字符串b,有多少種可以在字符串a中完成匹配。

例如:a="00010001",b="??",字符串b可能的字符串是"00","01","10","11",只有"11"沒有出現在字符串a中,所以輸出3。

輸入描述:輸入包括兩行,第一行是字符串a,長度在1-50,第二行是字符串b,長度是1-50,輸出為一個數,表示匹配數量。

 

解題:

1)Main函數編寫

 1 int main(int argc, const char* argv[]){
 2     char * str = malloc(sizeof(char)*MAXLEN);
 3     char * pattern = malloc(sizeof(char)*MAXLEN);
 4     scanf("%s",str);
 5     scanf("%s",pattern);
 6     int strlen = 0;
 7     while (str[strlen]!='\0') {
 8         ++strlen;
 9     }
10     int patternlen = 0;
11     while (pattern[patternlen]!='\0') {
12         ++patternlen;
13     }
14     char **p1 = malloc(sizeof(char*)*MAXLEN);
15     char **p2 = malloc(sizeof(char*)*MAXLEN);
16     for (int i = 0; i <= strlen - patternlen; ++i) {
17         p1[i] = str+i;
18     }
19     //sort(p1, 0,strlen-patternlen);
20     qsort(p1, strlen-patternlen+1, sizeof(char*), cmp);
21     int i = 0;
22     int j = 1;
23     p2[0] = p1[0];
24     while (j <= strlen - patternlen) {
25         if (cmp2(p2[i],p1[j], patternlen) == 0) {
26             ++j;
27             continue;
28         }
29         //p2[++i] = p1[j++];
30         ++i;
31         p2[i] = p1[j];
32         ++j;
33     }
34     strlen = i+1;
35     j = 0;
36     int ans = 0;
37     while(j<strlen){
38         if (match(p2[j], pattern, patternlen) == 0) {
39             ++ans;
40         }
41         ++j;
42     }
43     printf("%d\n",ans);
44     return 0;
45 }

 

2)自實現的后綴數組比較函數cmp(該cmp的傳入參數為const char*類型,方便作為標准庫函數qsort的參數傳入)

 1 int cmp(const void * x, const void * y){
 2     int i = 0;
 3     char * a = *(char**)x;
 4     char * b = *(char**)y;
 5     while (a[i]!='\0'&&b[i]!='\0') {
 6         if (a[i]<b[i]) {
 7             return -1;
 8         } else if(a[i] > b[i]){
 9             return 1;
10         } else {
11             ++i;
12         }
13     }
14     if (a[i]=='\0'&&b[i]=='\0') {
15         return 0;
16     } else if(a[i]=='\0'){
17         return -1;
18     } else {
19         return 1;
20     }
21 }

 

3)因為c語言無法給函數形參配置默認值,故需重新實現一個帶有長度限制的字符串比較函數

//或者使用int strncmp(const char * s1, const char * s2, size_t n)
1
int cmp2(char * a, char * b, int len){ 2 int i = 0; 3 while (a[i]!='\0'&&b[i]!='\0'&& i<len) { 4 if (a[i]<b[i]) { 5 return -1; 6 } else if(a[i] > b[i]){ 7 return 1; 8 } else { 9 ++i; 10 } 11 } 12 if (i==len) { 13 return 0; 14 } 15 if (a[i]=='\0'&&b[i]=='\0') { 16 return 0; 17 } else if(a[i]=='\0'){ 18 return -1; 19 } else { 20 return 1; 21 } 22 }

 

4)自實現的快速排序算法

 1 void sort(char** arr, int start, int end){
 2     if (end-start <= 0) {
 3         return;
 4     }
 5     char* pivot = arr[start];
 6     int i = start+1;
 7     int j = end;
 8     while (i<=j) {
 9         while (cmp(arr[i],pivot)<1) {
10             ++i;
11         }
12         while(cmp(arr[j],pivot)==1){
13             --j;
14         }
15         if (i>=j) {
16             break;
17         }
18         char * temp = arr[i];
19         arr[i] = arr[j];
20         arr[j] = temp;
21     }
22 
23     arr[start] = arr[j];
24     arr[j] = pivot;
25     sort(arr, start, j-1);
26     sort(arr, j+1, end);
27 }

 

總結:

1)c語言標准庫共包含15個頭文件

Header File Content
stdio.h 輸入和輸出, 包括scanf,printf,putchar,getchar,puts,gets,fopen,fclose,fread,fwrite等
stdlib.h

最常用的系統工具函數,包括

1)#define NULL (void*)0

2)內存管理函數

void * malloc(size_t size), void free(void * ptr)

3)數學函數

abs, labs, rand, srand

4)字符串轉換函數

atoi, atol, atof

5)搜索和排序函數

void qsort(void * base, size_t nmemb, size_t size, int (* compar)(const void *, const void *))、void * bsearch(const void * key, const void * base, size_t nmemb, size_t size, int (* compar)(const void *, const void *))

string.h

字符串處理,包括

1)內存管理函數

void * memset(void * dest, int c, size_t n), void * memcpy(void * dest, const void * src, size_t n), int memcmp(const void * s1, const void * s2, size_t n), void * memchr(const void * s, int c, size_t n)

2)字符串處理函數

char * strcat(char * deat, const char * src), char * strcpy(char * dest, const char * src), char * strncpy(char * dest, const char * src, size_t n), int strcmp(const char * s1, const char * s2), int strncmp(const char * s1, const char * s2, size_t n), size_t strlen(const char * s), char * strtok(char * s1, const char * s2), char * strstr(const char * s1, const char * s2), char * strpbrk(const char * s1, const char * s2), char * strchr(const char * s, int c), char * strrchr(const char * s, int c)

math.h

數學函數,包括

1)指數與對數 exp, pow, sqrt, log, log10

2)取整 ceil, floor

3)取絕對值 fabs

ctype.h 字符類測試,包括大小寫轉換 tolower(c), toupper(c)
time.h 時間和日期, clock_t clock(void), double difftime(time_t time1, time_t time0)
error.h 定義錯誤代碼,perror(const char * s)
stddef.h 一些常數、類型和變量
assert.h 斷言,assert(int x), abort()函數使程序異常終止
float.h 浮點數運算
limits.h 定義整數數據類型的取值范圍
locate.h 本土化
setjmp.h 非局部跳轉
signal.h 信號
stdarg.h 可變參數列表

 

其中stdlib.h庫有比較重要的排序和搜索函數,string.h庫有重要的字符串比較、連接、復制、找子串函數,對字符串匹配有重要作用。

 

2)qsort的形參有一個 void * , 該算法一個重點是指針的運用,這里我們說說void* 和 void**的區別

void*是一種特殊的指針類型,可用於存放任意對象的地址。void**即為void類型指針的指針,void***為void類型指針的指針的指針。*(void**)表示void指針的指針的解引用,表示一個指針,可用於存放一個地址;

cmp函數中形參類型是void *,表示的是傳入數組中某兩個比較值的地址,該題傳入的是后綴數組,數組中每個值都是一個字符串的首地址,故該值的地址即字符串地址的地址,又叫指針的指針,該對象說白了還是個地址,當然可以用void*存放。

在使用void*和void**時,需先將該類型轉換成具體類型,才能進一步引用。故將其轉換成char**表示char類型地址的地址,再將其解引用,就得到了字符的地址,表示一個字符串。

c語言指針偏移也需要注意⚠️

C語言指針偏移技巧(也是一個要注意的坑)

 


免責聲明!

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



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