- // algo4-1.cpp 实现算法4.6、4.7、4.8的程序
- #include"c1.h"
- #include"c4-1.h"
- #include"bo4-1.cpp"
- void get_next(SString T,int next[])
- { // 求模式串T的next函数值并存入数组next。算法4.7
- int i=1,j=0;
- next[1]=0;
- while(i<T[0])
- if(j==0||T[i]==T[j])
- {
- ++i;
- ++j;
- next[i]=j;
- }
- else
- j=next[j];
- }
- void get_nextval(SString T,int nextval[])
- { // 求模式串T的next函数修正值并存入数组nextval。算法4.8
- int i=1,j=0;
- nextval[1]=0;
- while(i<T[0])
- if(j==0||T[i]==T[j])
- {
- ++i;
- ++j;
- if(T[i]!=T[j])
- nextval[i]=j;
- else
- nextval[i]=nextval[j];
- }
- else
- j=nextval[j];
- }
- int Index_KMP(SString S,SString T,int pos,int next[])
- { // 利用模式串T的next函数求T在主串S中第pos个字符之后的位置的KMP算法。
- // 其中,T非空,1≤pos≤StrLength(S)。算法4.6
- int i=pos,j=1;
- while(i<=S[0]&&j<=T[0])
- if(j==0||S[i]==T[j]) // 继续比较后继字符
- {
- ++i;
- ++j;
- }
- else // 模式串向右移动
- j=next[j];
- if(j>T[0]) // 匹配成功
- return i-T[0];
- else
- return 0;
- }
- void main()
- {
- int i,*p;
- SString s1,s2; // 以教科书算法4.8之上的数据为例
- StrAssign(s1,"aaabaaaab");
- printf("主串为: ");
- StrPrint(s1);
- StrAssign(s2,"aaaab");
- printf("子串为: ");
- StrPrint(s2);
- p=(int*)malloc((StrLength(s2)+1)*sizeof(int)); // 生成s2的next数组空间
- get_next(s2,p); // 利用算法4.7,求得next数组,存于p中
- printf("子串的next数组为: ");
- for(i=1;i<=StrLength(s2);i++)
- printf("%d ",*(p+i));
- printf("/n");
- i=Index_KMP(s1,s2,1,p); // 利用算法4.6求得串s2在s1中首次匹配的位置i
- if(i)
- printf("主串和子串在第%d个字符处首次匹配/n",i);
- else
- printf("主串和子串匹配不成功/n");
- get_nextval(s2,p); // 利用算法4.8,求得next数组,存于p中
- printf("子串的nextval数组为: ");
- for(i=1;i<=StrLength(s2);i++)
- printf("%d ",*(p+i));
- printf("/n");
- printf("主串和子串在第%d个字符处首次匹配/n",Index_KMP(s1,s2,1,p));
- }
- // algo4-2.cpp 文本行编辑
- #include"c1.h"
- #include"c4-2.h" // 采用串的堆分配存储结构
- #include"bo4-2.cpp" // 串的堆分配基本操作
- #define MAX_LEN 25 // 文件最大行数
- #define LINE_LEN 75 // 每行字符数最大值+1
- #define NAME_LEN 20 // 文件名最大长度(包括盘符、路径)+1
- // 全局变量
- HString T[MAX_LEN];
- char str[LINE_LEN],filename[NAME_LEN]="";
- FILE *fp;
- int n=0; // 文本行数
- void Open()
- { // 打开文件(新或旧)
- if(filename[0]) // 文件已打开
- printf("已存在打开的文件/n");
- else
- {
- printf("请输入文件名(可包括盘符、路径,不超过%d个字符): ",NAME_LEN-1);
- scanf("%s",filename);
- fp=fopen(filename,"r"); // 以读的方式打开文件
- if(fp) // 已存在此文件
- {
- while(fgets(str,LINE_LEN,fp)) // 由文件读入1行字符成功
- {
- str[strlen(str)-1]=0; // 将换行符10强制改为串结束符0
- if(n>=MAX_LEN)
- {
- printf("文件太大/n");
- return;
- }
- StrAssign(T[n],str);
- n++;
- }
- fclose(fp); // 关闭文件
- }
- else
- printf("新文件/n");
- }
- }
- void List()
- { // 显示文本内容
- int i;
- for(i=0;i<n;i++)
- {
- printf("%d: ",i+1);
- StrPrint(T[i]);
- }
- }
- void Insert()
- { // 插入行
- int i,l,m;
- printf("在第l行前插m行,请输入l m: ");
- scanf("%d%d%*c",&l,&m);
- if(n+m>MAX_LEN)
- {
- printf("插入行太多/n");
- return;
- }
- if(n>=l-1&&l>0)
- {
- for(i=n-1;i>=l-1;i--)
- T[i+m]=T[i];
- n+=m;
- printf("请顺序输入待插入内容:/n");
- for(i=l-1;i<l-1+m;i++)
- {
- gets(str);
- InitString(T[i]);
- StrAssign(T[i],str);
- }
- }
- else
- printf("行超出范围/n");
- }
- void Delete()
- { // 删除行
- int i,l,m;
- printf("从第l行起删除m行,请输入l m: ");
- scanf("%d%d",&l,&m);
- if(n>=l+m-1&&l>0)
- {
- for(i=l-1+m;i<n;i++)
- {
- free(T[i-m].ch);
- T[i-m]=T[i];
- }
- for(i=n-m;i<n;i++)
- InitString(T[i]);
- n-=m;
- }
- else
- printf("行超出范围/n");
- }
- void Copy()
- { // 拷贝行
- int i,l,m,k;
- printf("把第l行开始的m行插在原k行之前,请输入l m k: ");
- scanf("%d%d%d",&l,&m,&k);
- if(n+m>MAX_LEN)
- {
- printf("拷贝行太多/n");
- return;
- }
- if(n>=k-1&&n>=l-1+m&&(k>=l+m||k<=l))
- {
- for(i=n-1;i>=k-1;i--)
- T[i+m]=T[i];
- n+=m;
- if(k<=l)
- l+=m;
- for(i=l-1;i<l-1+m;i++)
- {
- InitString(T[i+k-l]);
- StrCopy(T[i+k-l],T[i]);
- }
- }
- else
- printf("行超出范围/n");
- }
- void Modify()
- { // 修改行
- int i;
- printf("请输入待修改的行号: ");
- scanf("%d%*c",&i);
- if(i>0&&i<=n) // 行号合法
- {
- printf("%d: ",i);
- StrPrint(T[i-1]);
- printf("请输入新内容: ");
- gets(str);
- StrAssign(T[i-1],str);
- }
- else
- printf("行号超出范围/n");
- }
- void Search()
- { // 查找字符串
- int i,k,f=1; // f为继续查找标志
- char b[2];
- HString s;
- printf("请输入待查找的字符串: ");
- scanf("%s%*c",str);
- InitString(s);
- StrAssign(s,str);
- for(i=0;i<n&&f;i++) // 逐行查找
- {
- k=1; // 由每行第1个字符起查找
- while(k)
- {
- k=Index(T[i],s,k); // 由本行的第k个字符开始查找
- if(k) // 找到
- {
- printf("第%d行: ",i+1);
- StrPrint(T[i]);
- printf("第%d个字符处找到。继续查找吗(Y/N)? ",k);
- gets(b);
- if(b[0]!='Y'&&b[0]!='y') // 中断查找
- {
- f=0;
- break;
- }
- else
- k++;
- }
- }
- }
- if(f)
- printf("没找到/n");
- }
- void Replace()
- { // 替换字符串
- int i,k,f=1; // f为继续替换标志
- char b[2];
- HString s,t;
- printf("请输入待替换的字符串: ");
- scanf("%s%*c",str);
- InitString(s);
- StrAssign(s,str);
- printf("替换为: ");
- scanf("%s%*c",str);
- InitString(t);
- StrAssign(t,str);
- for(i=0;i<n&&f;i++) // 逐行查找、替换
- {
- k=1; // 由每行第1个字符起查找
- while(k)
- {
- k=Index(T[i],s,k); // 由本行的第k个字符开始查找
- if(k) // 找到
- {
- printf("第%d行: ",i+1);
- StrPrint(T[i]);
- printf("第%d个字符处找到。是否替换(Y/N)? ",k);
- gets(b);
- if(b[0]=='Y'||b[0]=='y')
- {
- StrDelete(T[i],k,StrLength(s));
- StrInsert(T[i],k,t);
- }
- printf("继续替换吗(Y/N)?");
- gets(b);
- if(b[0]!='Y'&&b[0]!='y') // 中断查找、替换
- {
- f=0;
- break;
- }
- else
- k+=StrLength(t);
- }
- }
- }
- if(f)
- printf("没找到/n");
- }
- void Save()
- { // 存盘
- int i,j;
- fp=fopen(filename,"w"); // 以写的方式重新打开文件
- if(fp) // 打开文件成功
- {
- for(i=0;i<n;i++)
- { // 依次将每行存入文件
- for(j=0;j<T[i].length;j++) // 依次存入每个字符
- fputc(T[i].ch[j],fp);
- fputc(10,fp); // 存入换行符
- ClearString(T[i]); // 释放串空间
- }
- fclose(fp); // 关闭文件
- }
- else
- printf("存盘失败/n");
- }
- void main()
- {
- Status s=TRUE;
- int i,k;
- for(i=0;i<MAX_LEN;i++) // 初始化串
- InitString(T[i]);
- while(s)
- {
- printf("请选择: 1.打开文件(新或旧) 2.显示文件内容/n");
- printf(" 3.插入行 4.删除行 5.拷贝行 6.修改行/n");
- printf(" 7.查找字符串 8.替换字符串/n");
- printf(" 9.存盘退出 0.放弃编辑/n");
- scanf("%d",&k);
- switch(k)
- {
- case 1: Open();
- break;
- case 2: List();
- break;
- case 3: Insert();
- break;
- case 4: Delete();
- break;
- case 5: Copy();
- break;
- case 6: Modify();
- break;
-
- // algo4-3.cpp 根据书目文件bookinfo.txt生成书名关键词索引文件bookidx.txt,
- // 为运行algo4-4.cpp做准备,算法4.9~4.14
- #include"c1.h"
- typedef int ElemType;
- #include"c2-5.h"
- #include"bo2-6.cpp"
- #include"c4-2.h"
- #include"bo4-2.cpp"
- #define MaxKeyNum 25 // 索引表的最大容量(关键词的最大数目)
- #define MaxLineLen 52 // 书目串(书目文件的1行)buf的最大长度
- #define MaxNoIdx 10 // 非索引词(也是一个书目中关键词)的最大数目
- struct WordListType // 一个书目的词表(顺序表)和非索引词表(有序表)共用类型
- {
- char *item[MaxNoIdx]; // 词表(字符串)指针数组
- int last; // 词的数量
- };
- struct IdxTermType // 索引项类型
- {
- HString key; // 关键词(堆分配类型,c4-2.h)
- LinkList bnolist; // 存放书号索引的链表(c2-5.h)
- };
- struct IdxListType // 索引表类型(有序表)
- {
- IdxTermType item[MaxKeyNum+1]; // 索引项数组类型
- int last; // 关键词的个数
- };
- // 全局变量
- char buf[MaxLineLen+1]; // 当前书目串(包括'/0')
- WordListType wdlist,noidx; // 暂存一种书的词表,非索引词表
- void InitIdxList(IdxListType &idxlist)
- { // 初始化操作,置索引表idxlist为空表,且在idxlist.item[0]设一空串
- idxlist.last=0;
- InitString(idxlist.item[0].key); // 初始化[0]单元,函数在bo4-2.cpp中
- InitList(idxlist.item[0].bnolist); // 初始化[0]单元,函数在bo2-6.cpp中
- }
- void ExtractKeyWord(int &BookNo)
- { // 从buf中提取书名关键词到词表wdlist,书号存入BookNo
- int i,l,f=1; // f是字符串buf结束标志 0:结束 1:未结束
- char *s1,*s2;
- for(i=1;i<=wdlist.last;i++)
- { // 释放上一个书目在词表wdlist的存储空间
- free(wdlist.item[i]);
- wdlist.item[i]=NULL;
- }
- wdlist.last=0; // 初始化词表wdlist的词数量
- BookNo=atoi(buf); // 将前几位数字转化为整数,赋给书号BookNo
- s1=&buf[4]; // s1指向书名的首字符
- while(f)
- { // 提取书名关键词到词表wdlist
- s2=strchr(s1,' '); // s2指向s1后的第一个空格,如没有,返回NULL
- if(!s2) // 到串尾(没空格)
- {
- s2=strchr(s1,'/12'); // s2指向buf的最后一个字符(回车符10)
- f=0;
- }
- l=s2-s1; // 单词长度
- if(s1[0]>='A'&&s1[0]<='Z') // 单词首字母为大写
- { // 写入词表
- wdlist.item[wdlist.last]=(char *)malloc((l+1)*sizeof(char)); // 生成串空间(包括'/0')
- for(i=0;i<l;i++)
- wdlist.item[wdlist.last][i]=s1[i]; // 写入词表
- wdlist.item[wdlist.last][l]=0; // 串结束符
- for(i=0;i<noidx.last&&(l=strcmp(wdlist.item[wdlist.last],noidx.item[i]))>0;i++);
- // 查找是否为非索引词
- if(!l) // 是非索引词
- {
- free(wdlist.item[wdlist.last]); // 从词表中删除该词
- wdlist.item[wdlist.last]=NULL;
- }
- else
- wdlist.last++; // 词表长度+1
- }
- s1=s2+1; // s1移动到下一个单词的首字符处
- };
- }
- void GetWord(int i,HString &wd)
- { // 用wd返回词表wdlist中第i个关键词,算法4.11
- StrAssign(wd,wdlist.item[i]); // 生成关键字字符串 bo4-2.cpp
- }
- int Locate(IdxListType &idxlist,HString wd,Status &b)
- { // 在索引表idxlist中查询是否存在与wd相等的关键词。若存在,则返回其
- // 在索引表中的位置,且b取值TRUE;否则返回插入位置,且b取值FALSE,算法4.12
- int i,m;
- for(i=idxlist.last;(m=StrCompare(idxlist.item[i].key,wd))>0;--i); // bo4-2.cpp
- if(m==0) // 找到
- {
- b=TRUE;
- return i;
- }
- else
- {
- b=FALSE;
- return i+1;
- }
- }
- void InsertNewKey(IdxListType &idxlist,int i,HString wd)
- { // 在索引表idxlist的第i项上插入新关键词wd,并初始化书号索引的链表为空表,算法4.13
- int j;
- for(j=idxlist.last;j>=i;--j) // 后移索引项
- idxlist.item[j+1]=idxlist.item[j];
- InitString(idxlist.item[i].key); // bo4-2.cpp
- StrCopy(idxlist.item[i].key,wd); // 串拷贝插入新的索引项 bo4-2.cpp
- InitList(idxlist.item[i].bnolist); // 初始化书号索引表为空表 bo2-6.cpp
- idxlist.last++;
- }
- void InsertBook(IdxListType &idxlist,int i,int bno)
- { // 在索引表idxlist的第i项中插入书号为bno的索引,算法4.14
- Link p;
- MakeNode(p,bno); // 分配结点 bo2-6.cpp
- p->next=NULL;
- Append(idxlist.item[i].bnolist,p); // 插入新的书号索引 bo2-6.cpp
- }
- void InsIdxList(IdxListType &idxlist,int bno)
- { // 将书号为bno的关键词插入索引表,算法4.10
- int i,j;
- Status b;
- HString wd;
- InitString(wd); // bo4-2.cpp
- for(i=0;i<wdlist.last;i++)
- {
- GetWord(i,wd);
- j=Locate(idxlist,wd,b); // 关键词的位置或待插入的位置(当索引表中不存在该词)
- if(!b) // 索引表中不存在关键词wd
- InsertNewKey(idxlist,j,wd); // 在索引表中插入新的索引项
- InsertBook(idxlist,j,bno); // 插入书号索引
- }
- }
- void PutText(FILE *f,IdxListType idxlist)
- { // 将生成的索引表idxlist输出到文件f
- int i,j;
- Link p;
- fprintf(f,"%d/n",idxlist.last);
- for(i=1;i<=idxlist.last;i++)
- {
- for(j=0;j<idxlist.item[i].key.length;j++)
- fprintf(f,"%c",idxlist.item[i].key.ch[j]); // HString类型串尾没有/0,只能逐个字符输出
- fprintf(f,"/n%d/n",idxlist.item[i].bnolist.len);
- p=idxlist.item[i].bnolist.head;
- for(j=1;j<=idxlist.item[i].bnolist.len;j++)
- {
- p=p->next;
- fprintf(f,"%d ",p->data);
- }
- fprintf(f,"/n");
- }
- }
- void main()
- { // 算法4.9
- FILE *f; // 任何时间最多打开一个文件
- IdxListType idxlist; // 索引表
- int BookNo; // 书号变量
- int k;
- if(!(f=fopen("NoIdx.txt","r"))) // 打开非索引词文件
- exit(OVERFLOW);
- fscanf(f,"%d",&noidx.last); // 读取非索引词个数
- for(k=0;k<noidx.last;k++) // 把非索引词文件的内容依次拷到noidx中
- {
- fscanf(f,"%s",buf);
- noidx.item[k]=(char*)malloc((strlen(buf)+1)*sizeof(char));
- strcpy(noidx.item[k],buf);
- }
- fclose(f); // 关闭非索引词文件
- if(!(f=fopen("BookInfo.txt","r"))) // 打开书目文件
- exit(FALSE);
- InitIdxList(idxlist); // 设索引表idxlist为空,并初始化[0]单元
- while(fgets(buf,MaxLineLen,f)) // 由书目文件读取1行信息到buf成功
- {
- ExtractKeyWord(BookNo);//将buf中的书号存入BookNo,关键词提取到词表(当前书目的关键词表)中
- InsIdxList(idxlist,BookNo); // 将书号为BookNo的关键词及书号插入索引表idxlist中
- }
- fclose(f); // 关闭书目文件
- if(!(f=fopen("BookIdx.txt","w"))) // 打开书名关键词索引文件
- exit(INFEASIBLE);
- PutText(f,idxlist); // 将生成的索引表idxlist输出到书名关键词索引文件
- fclose(f); // 关闭书名关键词索引文件
- }
- break;
- case 8: Replace();
- break;
- case 9: Save();
- case 0: s=FALSE;
- }
- }
- }
- // algo4-4.cpp 根据algo4-3.cpp产生的文件,索引查询图书
- #include"c1.h"
- typedef int ElemType;
- #include"c2-5.h"
- #include"bo2-6.cpp"
- #include"c4-2.h"
- #include"bo4-2.cpp"
- #define MaxBookNum 10 // 假设只对10个书名建索引表
- #define MaxKeyNum 25 // 索引表的最大容量(关键词的最大数目)
- #define MaxLineLen 46 // 书名的最大长度
- struct IdxTermType // 索引项类型
- {
- HString key; // 关键词(堆分配类型,c4-2.h)
- LinkList bnolist; // 存放书号索引的链表(c2-5.h)
- };
- struct IdxListType // 索引表类型(有序表)
- {
- IdxTermType item[MaxKeyNum+1]; // 索引项数组类型
- int last; // 关键词的个数
- };
- struct BookTermType // 书目项类型
- {
- char bookname[MaxLineLen+1]; // 书名串(包括'/0')
- int bookno; // 书号
- };
- struct BookListType // 书目表类型(有序表)
- {
- BookTermType item[MaxBookNum]; // 书目项数组类型
- int last; // 书目的数量
- };
- void main()
- {
- FILE *f; // 任何时间最多打开一个文件
- IdxListType idxlist; // 索引表
- BookListType booklist; // 书目表
- char buf[MaxLineLen+5]; // 当前书目串(包括书号和'/0')
- HString ch; // 索引字符串
- int BookNo; // 书号
- Link p; // 链表指针
- int i,j,k,flag=1; // flag是继续查询的标志
- InitString(ch); // 初始化HString类型的变量
- if(!(f=fopen("BookIdx.txt","r"))) // 打开书名关键词索引表文件
- exit(OVERFLOW);
- fscanf(f,"%d",&idxlist.last); // 书名关键词个数
- for(k=0;k<idxlist.last;k++) // 把关键词文件的内容拷到idxlist中
- {
- fscanf(f,"%s",buf);
- i=0;
- while(buf[i])
- buf[i++]=tolower(buf[i]); // 字母转为小写
- InitString(idxlist.item[k].key);
- StrAssign(idxlist.item[k].key,buf);
- InitList(idxlist.item[k].bnolist); // 初始化书号链表,bo2-6.cpp
- fscanf(f,"%d",&i);
- for(j=0;j<i;j++)
- {
- fscanf(f,"%d",&BookNo);
- MakeNode(p,BookNo); // 产生新的书号结点,bo2-6.cpp
- p->next=NULL; // 给书号结点的指针域赋值
- Append(idxlist.item[k].bnolist,p); // 在表尾插入新的书号结点,bo2-6.cpp
- }
- }
- fclose(f);
- if(!(f=fopen("BookInfo.txt","r"))) // 打开书目文件
- exit(FALSE);
- i=0;
- while(fgets(buf,MaxLineLen,f))
- { // 把书目文件的内容拷到booklist中
- booklist.item[i].bookno=atoi(buf); // 前几位数字为书号
- strcpy(booklist.item[i++].bookname,&buf[4]); // 将buf由书名开始的字符串拷贝到booklist中
- }
- booklist.last=i;
- while(flag)
- {
- printf("请输入书目的关键词(一个):");
- scanf("%s",buf);
- i=0;
- while(buf[i])
- buf[i++]=tolower(buf[i]); // 字母转为小写
- StrAssign(ch,buf);
- i=0;
- do
- {
- k=StrCompare(ch,idxlist.item[i++].key); // bo4-2.cpp
- }while(k&&i<=idxlist.last);
- if(!k) // 索引表中有此关键词
- {
- p=idxlist.item[--i].bnolist.head->next; // p指向索引表中此关键词相应链表的首元结点
- while(p)
- {
- j=0;
- while(j<booklist.last&&p->data!=booklist.item[j].bookno) // 在booklist中找相应的书号
- j++;
- if(j<booklist.last)
- printf("%3d %s",booklist.item[j].bookno,booklist.item[j].bookname);
- p=p->next; // 继续向后找
- }
- }
- else
- printf("没找到/n");
- printf("继续查找请输入1,退出查找请输入0:");
- scanf("%d",&flag);
- }
- }