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语言指针偏移技巧(也是一个要注意的坑)

 

posted @ 2020-02-21 10:14  thePacer  阅读(1472)  评论(0编辑  收藏  举报