串的匹配算法--C语言实现

串这种数据结构,使用是比较多的,但是它的一些方法在更高级的语言中,比如Java,Python中封装的比较完整了。在这里,我只写了串中使用最多的匹配算法,即串的定位操作。串的匹配算法常用的两种就是朴素匹配算法KMP匹配算法。代码亲测,可直接执行。

 

  1 #include<stdio.h>
  2 
  3 /*字符串长度*/
  4 int StringLength(char *L)
  5 {
  6     int i = 0;                //记录位置
  7     int count = 0;            //计数器,记录长度
  8     while(L[i])                //判断当前位置是否为空
  9     {
 10         count++;            //长度加1
 11         i++;                //计数器加1
 12     }
 13     return count;            //返回长度
 14 }
 15 
 16 /*朴素匹配算法*/
 17 int Index(char *S, char *T)                    //S为主串,T为子串
 18 {
 19     int Slength = StringLength(S);            //获得主串S的长度
 20     int Tlength = StringLength(T);            //获得子串T的长度
 21     int i = 0;                                //记录主串S当前位置
 22     int j = 0;                                //记录子串T当前位置
 23 //    int count = 0;
 24     printf("朴素匹配算法中j回溯的值为:");
 25     while(i < Slength && j < Tlength)        //确保两个字符串的当前位置均小于其长度
 26     {
 27 //        printf("%d ", j);
 28 //        count++;
 29         if(S[i] == T[j])                    //判断主串S当前位置与子串T当前位置的字符是否相等
 30         {
 31             i++;                            //主串S的当前位置加1(后移)
 32             j++;                            //子串T的当前位置加1(后移)
 33         }
 34         else                                //如果两字符串的当前位置字符不等
 35         {
 36             i = i - j + 1;                    //主串S的当前位置i回溯到j==0时i位置的下一位置
 37             j = 0;                            //子串T的当前位置j归0
 38         }
 39     }    
 40 //    printf("\nj共变化了%d次\n", count);
 41                                             //循环比较完毕
 42     if(j == Tlength)                        //判断位置j的数值是否与子串T的长度相等
 43         return i - Tlength;                    //若是,说明搜索成功,返回T在S中出现的首位置
 44     else
 45         return -1;                            //若不是,说明T不存在与S中,返回-1
 46 }
 47 
 48 /*KMP算法*/
 49 void Get_Next(char *T, int next[])
 50 {
 51     int Tlength = StringLength(T);            //获得字符串T的长度
 52     int i = 0;                                //T的后缀位置
 53     int j = -1;                                //T的前缀位置
 54     next[0] = -1;                            //next数组的首位赋值为-1
 55     while(i < Tlength)                        //确保后缀位置小于串长
 56     {
 57         if(j == -1 || T[i] == T[j])            //如果j==-1,说明前缀已经回退到最前方
 58         {                                    //如果T[i] == T[j],说明当前前缀与后缀相等
 59             i++;                            //则后缀位置后移一位
 60             j++;                            //前缀位置后移一位
 61             next[i] = j;                    //当前后缀位置的next值为j
 62         }
 63         else
 64             j = next[j];                    //否则,j回退(还没完全搞懂回退到哪)
 65     }
 66 }
 67 
 68 int Index_KMP(char *S, char *T)
 69 {
 70     int Slength = StringLength(S);            //获得主串S的长度
 71     int Tlength = StringLength(T);            //获得子串T的长度
 72     int i = 0;                                //记录S的当前位置
 73     int j = 0;                                //记录T的当前位置
 74     int next[255];                                //next数组
 75     Get_Next(T, next);                        //调用Get_Next函数,为next赋值
 76     int count = 0;
 77 //    printf("KMP算法中j回溯的值为:");
 78     while(i < Slength && j < Tlength)
 79     {
 80 //        printf("%d ", j);
 81 //        count++;
 82         if(j == -1 || S[i] == T[j])            //如果j==-1,说明前缀已经回退到最前方
 83         {                                    //如果S[i] == T[j],说明主串与子串当前位置字符相等
 84             i++;                            //S的当前位置后移一位
 85             j++;                            //T的当前位置后移一位
 86         }
 87         else
 88         {
 89             j = next[j];                    //否则,j回退(未弄懂回退到哪)
 90         }
 91     }
 92 //    printf("\nj共变化了%d次\n", count);
 93     if(j == Tlength)                        //比较结束,判断j的值是否与T的长度相等
 94         return i - Tlength;                    //若是,返回T在S中出现的开始位置
 95     else
 96         return -1;                            //若不是,返回-1
 97 }
 98 
 99 /*KMP改进版算法*/
100 void Get_Next_Val(char *T, int nextVal[])
101 {
102     int Tlength = StringLength(T);            //获得子串T的长度
103     int i = 0;                                //记录后缀位置
104     int j = -1;                                //记录前缀位置
105     nextVal[0] = -1;                        //next数组第一位置赋值为-1
106     while(i < Tlength)
107     {
108         if(j == -1 || T[i] == T[j])            //同上
109         {
110             i++;                            //同上
111             j++;
112             if(T[i] != T[j])                //如果位置后移一位后的值不相等
113                 nextVal[i] = j;                //nextVal等于j
114             else                            //如果相等
115                 nextVal[i] = nextVal[j];    //当前后缀位置的nextVal值等于j位置的nextVal的值
116         }
117         else
118             j = nextVal[j];                    //同上
119     }
120 }
121 
122 int Index_KMP_Val(char *S, char *T)
123 {
124     int Slength = StringLength(S);            //获得主串S的长度
125     int Tlength = StringLength(T);            //获得子串T的长度
126     int i = 0;                                //记录S的当前位置
127     int j = 0;                                //记录T的当前位置
128     int next[255];                                //next数组
129     Get_Next_Val(T, next);                        //调用Get_Next函数,为next赋值
130     int count = 0;
131     printf("KMP_Val算法中j回溯的值为:");
132     while(i < Slength && j < Tlength)
133     {
134         printf("%d ", j);
135         count++;
136         if(j == -1 || S[i] == T[j])            //如果j==-1,说明前缀已经回退到最前方
137         {                                    //如果S[i] == T[j],说明主串与子串当前位置字符相等
138             i++;                            //S的当前位置后移一位
139             j++;                            //T的当前位置后移一位
140         }
141         else
142         {
143             j = next[j];                    //否则,j回退(未弄懂回退到哪)
144         }
145     }
146     printf("\nj共变化了%d次\n", count);
147     if(j == Tlength)                        //比较结束,判断j的值是否与T的长度相等
148         return i - Tlength;                    //若是,返回T在S中出现的开始位置
149     else
150         return -1;                            //若不是,返回-1
151 }
152 
153 
154     
155 void main()
156 {
157     char *S = "aaaaaaaaaaaaaaaaaaaaabcde";
158     char *T = "aaaaaaaaaaaaaaaaaaaaaaaax";
159     int pos;
160     pos = Index(S, T);
161     if(pos != -1)
162         printf("朴素匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos);
163     else
164         printf("朴素匹配算法:子串T不存在与主串S中\n");
165     printf("---------------------------------------------------------------------\n");
166     int pos_KMP;
167     pos_KMP = Index_KMP(S, T);
168     if(pos_KMP != -1)
169         printf("KMP匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos_KMP);
170     else
171         printf("KMP匹配算法:子串T不存在与主串S中\n");
172     printf("---------------------------------------------------------------------\n");
173     int pos_KMP_val;
174     pos_KMP_val = Index_KMP_Val(S, T);
175     if(pos_KMP_val != -1)
176         printf("KMP_Val匹配算法:子串T在主串S的下标为%d的位置上开始出现\n", pos_KMP_val);
177     else
178         printf("KMP_Val匹配算法:子串T不存在与主串S中\n");
179 }

 

posted @ 2019-02-09 17:53  哈哈瑞  阅读(1448)  评论(0编辑  收藏  举报