[数据结构]第四章--串(读书笔记2)

来源:互联网 发布:html json格式化输出 编辑:程序博客网 时间:2024/06/06 00:47

第四章-串

□4.2 串的表示和实现

// PROJECT04-02.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "c1.h"/*----------------------------------------串的堆分配储存表示------------------------------------------*/typedef struct{char* ch;/*若是非空串,则按串长分配存储区,否则ch为NULL*/int length;/*串长度*/}HString;Status StrAssign(HString *T,char *chars){ /* 生成一个其值等于串常量chars的串T */char *c = NULL;int i = 0;int count = 0;if (T->ch){free(T->ch);/*释放T原有的空间*/}count = strlen(chars); /* 求chars的长度i */if (count == 0){T->ch = NULL;T->length = 0;}else{if (!(T->ch = (char*)malloc(count + sizeof(char)))){exit(OVERFLOW);}T->length = count;}for(i = 0; i < T->length; i++){*(T->ch + i) = *(chars + i);}return OK;}Status StrCopy(HString *T,HString S){ /* 初始条件:串S存在。操作结果: 由串S复制得串T */int i;if((*T).ch){free((*T).ch); /* 释放T原有空间 */}(*T).ch = (char*)malloc(S.length * sizeof(char)); /* 分配串空间 */(*T).length = S.length;for(i=0; i < S.length; i++){*(T->ch + i) = *(S.ch + i);}return OK;}Status StrEmpty(HString S){ /* 初始条件: 串S存在。操作结果: 若S为空串,则返回TRUE,否则返回FALSE */if(S.length == 0 && S.ch == NULL){return TRUE;}else{return FALSE;}}int StrLength(HString S){return S.length;}int StrCompare(HString S,HString T){ /* 若S>T,则返回值>0;若S=T,则返回值=0;若S<T,则返回值<0 */int i;for (i = 0;i < S.length && i < T.length; i++){if (S.ch[i] != T.ch[i]){return S.ch[i] - T.ch[i];}}return S.length - T.length;}Status ClearString(HString *S){/*将S清为空串*/if ((*S).ch){free((*S).ch);(*S).ch = NULL;}(*S).length = 0;return OK;}Status Concat(HString *T, HString S1, HString S2){/*用T返回由S1和S2联结而成的新串*/int i;if((*T).ch){free((*T).ch); /* 释放T原有空间 */}if(!((*T).ch = (char*)malloc((S1.length + S2.length) * sizeof(char))) ){exit(OVERFlOW);}(*T).length = S1.length + S2.length;for(i = 0;i < S1.length; i++ ){(*T).ch[i] = S1.ch[i];}for(i = 0;i < S2.length; i++ ){(*T).ch[i + S1.length] = S2.ch[i];}return OK;}Status SubString(HString *Sub, HString S,int pos,int len){/* 用Sub返回串S的第pos个字符起长度为len的子串。 *//* 其中,1≤pos≤StrLength(S)且0≤len≤StrLength(S)-pos+1 */int i;if (pos < 1 || pos > S.length || len < 0 || len > S.length - pos + 1 ){return ERROR;}if (Sub->ch){/* 释放旧空间 */free(Sub->ch);Sub->ch = NULL;}if(len == 0){/* 空子串 */Sub->ch = NULL;Sub->length = 0;}else{/* 完整子串 */Sub->ch = (char*)malloc(len * sizeof(char));for (i = 0; i < len; i++){Sub->ch[i] = S.ch[pos + i - 1];}Sub->length = len;}return OK;}void InitString(HString *T){ /* 初始化(产生空串)字符串T。另加 */(*T).length = 0;(*T).ch = NULL;}int Index(HString S, HString T, int pos) /* 算法4.1 */{/* T为非空串。若主串S中第pos个字符之后存在与T相等的子串, *//* 则返回第一个这样的子串在S中的位置,否则返回0 */int n, m, i;HString sub;InitString(&sub);if(pos > 0){n = StrLength(S);m = StrLength(T);i = pos;while(i <= n - m + 1){SubString(&sub, S, i, m);if(StrCompare(sub, T) != 0){++i;}else{return i;}}}return 0;}Status StrDelete(HString *S,int pos,int len){ /* 从串S中删除第pos个字符起长度为len的子串 */int i;if((*S).length < pos + len -1){exit(ERROR);}for(i = pos-1; i <= (*S).length - len; i++){(*S).ch[i] = (*S).ch[i + len];}(*S).length -= len;(*S).ch = (char*)realloc((*S).ch,(*S).length * sizeof(char));return OK;}Status StrInsert(HString *S,int pos,HString T) /* 算法4.4 */{ /* 1≤pos≤StrLength(S)+1。在串S的第pos个字符之前插入串T */int i;if (pos >= 1 && pos >= StrLength(*S)+1){exit(ERROR);}(*S).ch = (char*)realloc((*S).ch,((*S).length + T.length) * sizeof(char));if(!(*S).ch){exit(OVERFLOW);}/* 为插入T而腾出位置 */for(i = (*S).length - 1 ;i >= pos-1; i--){(*S).ch[i+T.length] = (*S).ch[i];}for(i=0; i< T.length; i++){(*S).ch[i+pos-1] = T.ch[i];/* 插入T */}(*S).length += T.length;return OK;}Status Replace(HString *S,HString T,HString V){/* 初始条件: 串S,T和V存在,T是非空串(此函数与串的存储结构无关) *//* 操作结果: 用V替换主串S中出现的所有与T相等的不重叠的子串 */int i=1; /* 从串S的第一个字符起查找串T */if(StrEmpty(T)){ /* T是空串 */return ERROR;}do{i = Index(*S,T,i);if(i){ /* 串S中存在串T */StrDelete(S,i,T.length);/* 删除该串T */StrInsert(S,i,V); /* 在原串T的位置插入串V */i += StrLength(V); /* 在插入的串V后面继续查找串T */}}while(i);return OK;}void DestroyString(){ /* 堆分配类型的字符串无法销毁 */}void StrPrint(HString T){ /* 输出T字符串。另加 */int i;for(i = 0; i < T.length; i++){printf("%c", T.ch[i]);}printf("\n");}int _tmain(int argc, _TCHAR* argv[]){int i;char c,*p="God bye!",*q="God luck!";HString t,s,r;InitString(&t); /* HString类型必需初始化 */InitString(&s);InitString(&r);StrAssign(&t,p);printf("串t为: ");StrPrint(t);printf("串长为%d 串空否?%d(1:空 0:否)\n",StrLength(t),StrEmpty(t));StrAssign(&s,q);printf("串s为: ");StrPrint(s);i=StrCompare(s,t);if(i<0)c='<';else if(i==0)c='=';elsec='>';printf("串s%c串t\n",c);Concat(&r,t,s);printf("串t联接串s产生的串r为: ");StrPrint(r);StrAssign(&s,"oo");printf("串s为: ");StrPrint(s);StrAssign(&t,"o");printf("串t为: ");StrPrint(t);Replace(&r,t,s);printf("把串r中和串t相同的子串用串s代替后,串r为:\n");StrPrint(r);ClearString(&s);printf("串s清空后,串长为%d 空否?%d(1:空 0:否)\n",StrLength(s),StrEmpty(s));SubString(&s,r,6,4);printf("串s为从串r的第6个字符起的4个字符,长度为%d 串s为: ",s.length);StrPrint(s);StrCopy(&t,r);printf("复制串t为串r,串t为: ");StrPrint(t);StrInsert(&t,6,s);printf("在串t的第6个字符前插入串s后,串t为: ");StrPrint(t);StrDelete(&t,1,5);printf("从串t的第1个字符起删除5个字符后,串t为: ");StrPrint(t);printf("%d是从串t的第1个字符起,和串s相同的第1个子串的位置\n",Index(t,s,1));printf("%d是从串t的第2个字符起,和串s相同的第1个子串的位置\n",Index(t,s,2));return 0;}

□4.3 串的模式匹配算法
求子串位置的定位函数Index(S,T,pos)
子串的定位操作通常称作串的模式匹配,是各种串处理系统中最重要的操作之一。在Index这个函数中,分别利用计数指针i和j指示主串S和模式串T中当前正待比较的字符位置。算法的基本思想是:从主串S的第pos各字符起和模式的第一个字符比较之,若相等则继续逐个比较后续字符;否则从主串的下一个字符起再重新和模式的字符比较之。

□4.3.2 模式匹配的一种改进算法
克努特-莫里斯-普拉特操作(KMP算法)
其改进在于每当一趟匹配过程中出现字符比较不等时,不需回溯i指针,而是利用已经得到的"部分匹配"的结果将模式向右"滑动"尽可能远的一段距离后,继续进行比较。
KMP算法仅当模式与主串之间存在许多"部分匹配"的情况下才显得比算法4.5快得多。但是KMP算法的最大特点就是指示主串的指针不需回溯。
next[j]表明当模式中第j个字符与主串中相应字符失配时,在模式中需要重新和主串中该字符进行比较的字符的位置。匹配过程如下:假设以指针i和j分别指示主串和模式中正待比较的字符,令i的初值为pos,j的初值为1。若在匹配过程中si = pj,则i和j分别增1,否则i不变,而j退到next[j]的位置再比较,若相等,则指针各自增1,否则j再退到下一个next值的位置,依次类推,直至下列两种可能:一种是j退到某个next值时比较相等,则指针各自增1,继续进行匹配;另一种是j退到值为0,则此时需将模式继续向右滑动一个位置。即从主串的下一个字符Si+1起和模式重新开始匹配。虽然该算法的时间复杂度是O(n*m),但在一般情况下,其实际的执行时间近似于O(n+m),因此至今仍被采用。KMP算法仅当模式与主串之间存在许多"部分匹配"的情况下才显得快得多。KMP算法的最大特点是指示主串的指针不需回溯,整个匹配过程中,对主串仅需从头至尾扫描一遍,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,而无需回头重读。

原创粉丝点击