数据结构第四章学习小结
第四章主要学习了串和数组,串中最重要的内容就是KMP算法和BF算法,BF算法会好理解一点,但是时间复杂度较大,KMP算法虽然理解起来有点难,但是弄懂了之后就会发现用起来比BF算法方便很多,时间复杂度也会小很多。其次,还学了特殊矩阵的压缩存储,这种压缩存储对于一些特殊矩阵(对称,三角,对角矩阵)的存储有很大的帮助,可以节省很大的空间。
PTA上的两道编程,第一道是串的模式匹配,刚开始打的时候想试试BF算法,但是发现如果 i 和 j 从1开始的话,第二个测试点试过不了的,都改成从0开始后,就只有最后一个测试点运行超时,这个问题我查了一下,一般情况下,BF算法时间复杂度为O(m*n),数据量不大时候,执行时间近似为O(m+n),但如果是庞大数据,那它的效率就很低了,最后那个测试点的数据量很大,并且,这两个字符串从第一个字符比较一直不匹配,而模式串一直回溯到 j=0 ,这样工作量很大,所以BF算法提交之后在这个测试点是运行超时的。
代码如下:
1 int Index_BF(string s,string t) 2 { 3 int i = 0; 4 int j = 0; 5 while(i<=strlen(S)&&j<=strlen(T)) 6 { 7 if(S[i]==T[j]) 8 { 9 i++; 10 j++; 11 } 12 else 13 { 14 if(j==0) 15 { 16 j++; 17 } 18 else 19 { 20 i=i-j+2; 21 j=1; 22 } 23 24 } 25 } 26 if(j>strlen(T)) 27 { 28 return i-strlen(T); 29 } 30 else return 0; 31 }
后来我照着SPOC上的视频打了一遍代码,发现用char *做函数参数是=时只能过一个测试点,改为string类型后,全部测试点都可以过,不会出现运行超时的问题,主要是因为kmp算法减少了字符串查找过程中的回退,尽可能减少不用的操作,算法复杂度是O(n+m)。
代码如下:
1 void BuildMatch( string pattern, int *match ) 2 { 3 Position i, j; 4 int m = pattern.length(); 5 match[0] = -1; 6 7 for ( j=1; j<m; j++ ) { 8 i = match[j-1]; 9 while ( (i>=0) && (pattern[i+1]!=pattern[j]) ) 10 i = match[i]; 11 if ( pattern[i+1]==pattern[j] ) 12 match[j] = i+1; 13 else match[j] = -1; 14 } 15 } 16 17 Position KMP( string k, string pattern ) 18 { 19 int n = k.length(); 20 int m = pattern.length(); 21 Position s, p, *match; 22 23 if ( n < m ) return NotFound; 24 match = new Position[m]; 25 BuildMatch(pattern, match); 26 s = p = 0; 27 while ( s<n && p<m ) { 28 if ( k[s]==pattern[p] ) { 29 s++; p++; 30 } 31 else if (p>0) p = match[p-1]+1; 32 else s++; 33 } 34 return ( p==m )? (s-m+1) : NotFound; 35 }
第二个代码是求交集,不过这次的两个集合是无序的,所以需要先给两个集合排序,开始的时候我自己打了两个sort函数,发现过不了最后那个测试点,会显示运行超时的错误,后来我查了下资料,改用了<algorithm>库中的sort的函数,此时全部测试点都可以通过,这个sort函数的时间复杂度为n*log2n,想了解的同学可以去这个链接看看https://baike.baidu.com/item/sort%E5%87%BD%E6%95%B0/11042699?fr=aladdin。
代码如下:
1 void sort(int a[],int n) 2 { 3 int i,j,t; 4 for(i=0;i<n;i++) 5 { 6 for(j=0;j<n-1-i;j++) 7 { 8 if(a[j]>a[j+1]) 9 { 10 t = a[j]; 11 a[j] = a[j+1]; 12 a[j+1] = t; 13 } 14 } 15 } 16 } 17 18 void sort(int a[],int n) 19 { 20 int i,j,p,t; 21 for(i=0;i<n-1;i++) 22 { 23 p = i; 24 for(j=i+1;j<n;j++) 25 { 26 if(a[j]<a[p]) p=j; 27 } 28 if(p!=i) 29 { 30 t = a[p]; 31 a[p]=a[i]; 32 a[i]=t; 33 } 34 } 35 } 36 37 38 void Sort(int a[],int n) 39 { 40 int i,j,temp=a[0]; 41 for(i=0;i<n-1;i++) 42 { 43 for(j=i+1;j<n;j++) 44 { 45 if(a[j]<a[i]) 46 { 47 temp = a[i]; 48 a[i] = a[j]; 49 a[j] = temp; 50 } 51 } 52 } 53 }
这三个函数都是运行超时的问题,下面这份代码运用了<algorithm>库中的函数,所有的测试点都可以过
1 #include <iostream> 2 #include <algorithm> 3 using namespace std; 4 5 int main() 6 { 7 int a[100000],b[100000],c[100000]; 8 int n,m; 9 cin >> n >> m; 10 int i,j,k=0; 11 for(i=0;i<n;i++) 12 { 13 cin >> a[i]; 14 } 15 for(i=0;i<m;i++) 16 { 17 cin >> b[i]; 18 } 19 sort(a,a+n); 20 sort(b,b+m); 21 for(i=0,j=0;i<n&&j<m;) 22 { 23 if(a[i]==b[j]) 24 { 25 c[k++]=a[i]; 26 i++; 27 j++; 28 } 29 else if(a[i]>b[j]) 30 { 31 j++; 32 } 33 else 34 { 35 i++; 36 } 37 } 38 cout << k <<endl; 39 for(i=0;i<k;i++) 40 { 41 if(i==0) cout << c[i]; 42 else 43 { 44 cout << " " <<c[i]; 45 } 46 } 47 return 0; 48 }
这章的学习我在CSDN和博客园上找到了许多有利于学习的博客,推荐大家在遇到不懂的知识时可以去上面查一查
大家对KMP算法还不是很会的话可以去看看这个博客,讲的很清楚https://blog.csdn.net/dark_cy/article/details/88698736
我在打求交集的时候最开始想用链表实现,就去找了一下给链表排序的方法,有兴趣的同学可以看看https://blog.csdn.net/qq_33835221/article/details/85988596
虽然现在可以理解KMP算法了,但是无法完全独自打出KMP算法的全部代码,争取在下一章的学习中可以在学习新知识的同时可以复习一些以前学的知识,多自己去复现一些书上的代码。