240 likes | 397 Views
题4 .12. 题4 .13. 题4 .25. 题4 .20. 题4 .28. 题4 .29. 题4 .30. 题 4.12. 利用已知串的 五种基本操作 实现串的置换操作。. pos. pos. i. S 串. sub. T 串. V 串. news 串. sub. V 串. StringType Replace (StringType S, StringType T,
E N D
题4.12 题4.13 题4.25 题4.20 题4.28 题4.29 题4.30
题4.12 利用已知串的五种基本操作实现串的置换操作。 pos pos i S 串 sub T 串 V 串 news 串 sub V 串
StringType Replace (StringType S, StringType T, StringType V ) { // T为非空串。若主串S中存在与 T相等的子串,则均以串V替换之。 // 本算法返回被置换后的新串。 n = StrLength(S); m = StrLength(T); i = pos = 1; StrAssign(news, ); while ( i <= n-m+1) { SubString (sub, S, i, m); if (StrCompare(sub,T) != 0) ++i ; else { } } // while S中不再存在与T相等的子串 } // Replace ··· ··· ··· ···
// else news = Concat(news, SubString(S, pos, i-pos)); news = Concat(news, V); i = pos = i + m; // pos指示查询的起始位置; i指示子串的起始位置 // 结尾处理 news = Concat(news, SubString(S, pos, n-pos+1)); return news;
题4.13 从串S中删除所有和串T相同的子串。 此题的操作等同于“以空串置换串S中所有和串T相同的子串。” 显然,算法的目标是构造如上所画的一个新串。
StringType Delete (StringType S, StringType T) { // T为非空串。若主串S中存在与 T相等的子串,则删除之。 // 本算法返回被删后的 S串。 n = StrLength(S); m = StrLength(T); i = pos = 1; StrAssign(news, ); while ( i <= n-m+1) { SubString (sub, S, i, m); if (StrCompare(sub,T) != 0) ++i ; else { } } // while S中不再存在与T相等的子串 } // Delete ··· ··· ··· ···
// else news = Concat(news, SubString(S, pos, i-pos)); i = pos = i + m; // 结尾处理 news = Concat(news, SubString(S, pos, n-pos+1)); return news;
题4.20 从串S 中删除所有和串T 相同的子串。 此题的基本思想和题 4.13 相同,所不同的是要求在在串的定长存储表示中实现。 算法的目标是构造如上所画的一个新串。
删除之前的 S 串 k pos 删除之后的 S 串 算法的基本思想为: S[S[0]+1..S[0]+k-pos] = S[pos.. k-1] 具体写算法时,上述串的赋值是对单个字符进行的,因为在查询过程中,一旦指针 i“回退”,则说明上一次搜索的起始位置的字符肯定不会被删除。详细算法见下页。
void del_sub(SString S, SString T) { k=0; i=1; // k指示新串的当前长度,i指示S串中当前匹配的字符 while (i <= S[0]-T[0]+1) { j=1; while (j<=T[0] && S[i] = T[j] ) { ++i; ++j; } // 继续比较后继字符 if ( !(j > T[0])) //重新开始一轮匹配,并保存“前一字符” { i:=i-j+2; S[++k]:=S[i-1]; } } // while while (i <= S[0] ) { ++k; S[k..k+S[0]-i+1]:=S[i..S[0]]; } // 保存剩余串 S[0] = k+S[0]-i+1; }
题4.25 解此题的基本思想和题4.12相同,但需要在串的堆存储结构中实现。 由于堆存储结构是按串的实际长度分配空间,则首先需知道置换之后的串的长度。 因此解此题的基本步骤为: 1) 找出所有和 T串相同的子串,并记下它们的起始位置; 2) 计算置换之后的 S 串的长度; 3) 为置换后的串分配空间并逐段复制求得新的 S 串;
void repl(HString &S, HString T, HString V) { 初始化线性表Y为空表; // Y记录和T相同的子串 i=0; while (i <= S.length-T.length) 在S 中查找和 T 相同的子串,共有Y.length个,每一个子串在S 中的初始位置为Y.elem[k]; if (Y.length!=0) { n = S.length; S.length = n + Y.length*(V.length-T.length); ns.ch = new char[S.length]; 逐段复制子串到ns.ch; S.ch = ns.ch; } // if } // repl
void repl(HString &S, HString T, HString V) { Y.length = 0; i = 0; while (i <= S.length - T.length ) { j = 0; while (j<T.length && S.ch[i+j] = T.ch[j]) j++; if ( j < T.length ) i++; // 重新开始新一轮的匹配 else // 找到和T 相同的子串 { Y.elem[Y.length++] = i; i+=T.length; } }//while if ( Y.length != 0 ) { } } ……
n = S.length; S.length += Y.length*(T.length-V.length); ns.ch = new char[S.length+1]; k=1; i=0; spos=0; while(k<Y.length) { tpos=Y.elem[k]-1; len=tpos-spos; ns.ch[i..i+len] = S.ch[spos..tpos]; i+=len+1; ns.ch[i..i+V.length-1] = V.ch[0..V.length-1]; spos = Y.elem[k]+T.length; i+=V.length; k++; } ns.ch[i..S.length-1] = S.ch[spos..n-1]; S.ch = ns.ch;
T V spos tpos spos i+len i i i tpos=Y.elem[k]-1; len=tpos-spos; i+=len+1; spos = Y.elem[k]+T.length; i+=V.length;
void get_next(Lstring T) { p = T.head; q = NULL; p->next = NULL; while (p) { if ( !q || p->ch == q->ch ) { p = p->succ; if (!q) q = T.head; else q = q->succ; if ( p->ch == q->ch ) p->next = q->next; else p->next = q; } else q = q->next; } 题4.28
题4.29 Link index_L(Lstring S, Lstring T) { p = S.head; q = T.head; while ( p && q ) { if ( p->ch == q->ch ) { p = p->succ; q = q->succ; } else { q = q->next; if (!q) { q = T.head; p = p->succ; } }//while if (q) return NULL; else } …… // 回退找起始位置
p = p->next; q = T.head; while ( q->succ ) { p = p->next; q = q->succ; } return p;
题4.30 求串S中出现的第一个最长重复子串及其位置。 所谓“重复子串”指的是, SubString(S, i, len) == SubString(S, j, len) 1≤ i<j ≤StrLength(S), 1≤ len ≤StrLength(S)-j+1 例如: S=aaaaaaa的最长重复子串为 T=aaaaaa
分析: 此题可有多种解法。 一种比较直观的做法是: 在串 S 中取子串 SubString( S, i, len ) 和子串 SubString( S, i+1, StrLength(S)-i ) 相匹配。 假设 S 串的长度为 n, 则 len 的变化范围是从 n-1 到 1 , i 的变化范围是从 1 到 n - len 最坏情况下的时间复杂度为 O(n3)。 另一种作法是,利用 next 函数的特性, 可以使算法的时间复杂度减为 O(n2)。
因为 next[j]0表明: 在第 j 个字符之前存在一个长度为 next[j]-1 的重复子串。 由此,算法的基本思想为:求各子串 pat[i]=SubString(S,i,StrLength(S)-i+1) 的next 函数值,i=1, 2, …, StrLength(S)- 1并从中求最大值
例如: S=abaabaaabaaaab Pat[1]= abaabaaabaaaabnext值 0 1 1 22 3 4 52 3 4 5 2 2 Pat[2]= baabaaabaaaabnext值 0 1 1 12 3 4 12 3 4 1 1 Pat[3]= aabaaabaaaabnext值 0 1 2 12 3 3 45 6 7 3 Pat[4]= abaaabaaaabnext值 0 1 1 22 2 3 4 56 2
i=1; maxl=0; n=S[0]; while(n-i+1>maxl) { maxk=Max{Next(SubString(S, i ,n-i+1))}; if (maxk!=next[n] || S[n]!=S[i+maxk-1]) maxk--; if (maxk>maxl) { maxl=maxk; spos=i; } i++; }
算法的基本思想为: 求 pat[i] = SubString( S, i, n-i+1 ) i=1,2,…,n-1 的 next 函数值中的最大值。 i = 1; maxl = 0; spos = 0; n = S[0]; while ( n-i+1 > maxl ) { 求 pat[i] = SubString( S, i, n-i+1 ) 的 next[j]中 的最大值 len[i] = next[j]; if ( len[i] > maxl ) { maxl = len[i]; 记下子串pat[i] 的起始位置; } i++; }