算法设计

来源:互联网 发布:unity3d 制作2d动画 编辑:程序博客网 时间:2024/05/02 16:21
算法设计 1、[题目分析]判断字符串t是否是字符串s的子串,称为串的模式匹配,其基本思想是对串s和t各设一个指针i和j,i的值域是0..m-n,j的值域是0..n-1。初始值i和j均为0。模式匹配从s0和t0开始,若s0=t0,则i和j指针增加1,若在某个位置si!=tj,则主串指针i回溯到i=i-j+1,j仍从0开始,进行下一轮的比较,直到匹配成功(j>n-1),返回子串在主串的位置(i-j)。否则,当i>m-n则为匹配失败。 int index(char s[],t[],int m,n) //字符串s和t用一维数组存储,其长度分别为m和n。本算法求字符串t在字符串s中的第一次出现,如是,输出子串在s中的位置,否则输出0。 {int i=0,j=0; while (i<=m-n && j<=n-1) if (s[i]==t[j]){i++;j++;} //对应字符相等,指针后移。 else {i=i-j+1;j=0;} //对应字符不相等,I回溯,j仍为0。 if(i<=m-n && j==n) {printf(“t在s串中位置是%d”,i-n+1);return(i-n+1);}//匹配成功 else return(0); //匹配失败 }//算法index结束 main ()//主函数 {char s[],t[]; int m,n,i; scanf(“%d%d”,&m,&n); //输入两字符串的长度 scanf(“%s”,s); //输入主串 scanf(“%s”,t); //输入子串 i=index(s,t,m,n); }//程序结束 [程序讨论]因用C语言实现,一维数组的下标从0开始,m-1是主串最后一个字符的下标,n-1是t串的最后一个字符的下标。若匹配成功,最佳情况是s串的第0到第n-1个字符与t匹配,时间复杂度为o(n);匹配成功的最差情况是,每次均在t的最后一个字符才失败,直到s串的第m-n个字符成功,其时间复杂度为o((m-n)*n),即o(m*n)。失败的情况是s串的第m-n个字符比t串某字符比较失败,时间复杂度为o(m*n)。之所以串s的指针i最大到m-n,是因为在m-n之后,所剩子串长度已经小于子串长度n,故不必再去比较。算法中未讨论输入错误(如s串长小于t串长)。 另外,根据子串的定义,返回值i-n+1是子串在主串中的位置,子串在主串中的下标是i-n。 2.[问题分析]在一个字符串内,统计含多少整数的问题,核心是如何将数从字符串中分离出来。从左到右扫描字符串,初次碰到数字字符时,作为一个整数的开始。然后进行拼数,即将连续出现的数字字符拼成一个整数,直到碰到非数字字符为止,一个整数拼完,存入数组,再准备下一整数,如此下去,直至整个字符串扫描到结束。  int CountInt() // 从键盘输入字符串,连续的数字字符算作一个整数,统计其中整数的个数。 {int i=0,a[]; // 整数存储到数组a,i记整数个数  scanf(“%c”,&ch);// 从左到右读入字符串  while(ch!=‘#’) //‘#’是字符串结束标记   if(isdigit(ch))// 是数字字符   {num=0; // 数初始化    while(isdigit(ch)&& ch!=‘#’)// 拼数    {num=num*10+‘ch’-‘0’;     scanf(“%c”,&ch);     }    a[i]=num;i++;    if(ch!=‘#’)scanf(“%c”,&ch); // 若拼数中输入了‘#’,则不再输入    }// 结束while(ch!=‘#’)  printf(“共有%d个整数,它们是:”i);  for(j=0;jt.curlen,则向左移;若jmaxlen) {printf(“参数错误/n”);exit(0);} //检查参数及置换后的长度的合法性。 if(j=i+j-1;k--) s.ch[k+t.curlen-j]=s.ch[k]; else if (j>t.curlen) //s串中被替换子串的长度小于t串的长度。 for(k=i-1+j;k<=s.curlen-1;k++) s.ch[k-(j-t.curlen)]=s.ch[k]; for(k=0;kt.curlen) s.curlen=s.curlen-(j-t.curlen);else s.curlen=s.curlen+(t.curlen-j); }//算法结束 [算法讨论]若允许使用另一数组,在检查合法性后,可将s的第i个(不包括i)之前的子串复制到另一子串如s1中,再将t串接到s1串后面,然后将s的第i+j直到尾的部分加到s1之后。最后将s1串复制到s。主要语句有: for(k=0;ki-1+j;k--);//将子串第i+j-1个字符以后的子串复制到s1 s1.ch[l--]=s.ch[k] for(k=0;k=pos ;j--){*(p+x)=*p; p--;}//串s的pos后的子串右移,空出串t的位置。 q--; //指针q回退到串t的最后一个字符 for(j=1;j<=x;j++) *p--=*q--; //将t串插入到s的pos位置上 [算法讨论] 串s的结束标记('/0')也后移了,而串t的结尾标记不应插入到s中。 6.[题目分析]本题属于查找,待查找元素是字符串(长4),将查找元素存放在一维数组中。二分检索(即折半查找或对分查找),是首先用一维数组的“中间”元素与被检索元素比较,若相等,则检索成功,否则,根据被检索元素大于或小于中间元素,而在中间元素的右方或左方继续查找,直到检索成功或失败(被检索区间的低端指针大于高端指针)。下面给出类C语言的解法 typedef struct node {char data[4];//字符串长4 }node; 非递归过程如下: int binsearch(node string [];int n;char name[4]) //在有n个字符串的数组string中,二分检索字符串name。若检索成功,返回name在string中的下标,否则返回-1。 {int low = 0,high = n - 1;//low和high分别是检索区间的下界和上界 while(low <= high) {mid = (low + high) /2; //取中间位置 if(strcmp(string[mid],name) ==0) return (mid); //检索成功 else if(strcmp(string[mid],name)<0) low=mid+1; //到右半部分检索 else high=mid-1; //到左半部分检索 } return 0; //检索失败 }//算法结束 最大检索长度为log2n。 7. [题目分析]设字符串存于字符数组X中,若转换后的数是负数,字符串的第一个字符必为 '-',取出的数字字符,通过减去字符零('0')的ASCII值,变成数,先前取出的数乘上10加上本次转换的数形成部分数,直到字符串结束,得到结果。 long atoi(char X[]) //一数字字符串存于字符数组X中,本算法将其转换成数 {long num=0; int i=1; //i 为数组下标 while (X[i]!= '/0') num=10*num+(X[i++]-'0');//当字符串未到尾,进行数的转换 if(X[0]=='-') return (-num); //返回负数 else return ((X[0]-'0')*10+num); //返回正数,第一位若不是负号,则是数字 }//算法atoi结束 [算法讨论]如是负数,其符号位必在前面,即字符数组的x[0],所以在作转换成数时下标i从1 开始,数字字符转换成数使用X[i]-'0',即字符与'0'的ASCII值相减。请注意对返回正整数的处理。 8.[题目分析]本题要求字符串s1拆分成字符串s2和字符串s3,要求字符串s2“按给定长度n格式化成两端对齐的字符串”,即长度为n且首尾字符不得为空格字符。算法从左到右扫描字符串s1,找到第一个非空格字符,计数到n,第n个拷入字符串s2的字符不得为空格,然后将余下字符复制到字符串s3中。 void format (char *s1,*s2,*s3) //将字符串s1拆分成字符串s2和字符串s3,要求字符串s2是长n且两端对齐 {char *p=s1, *q=s2; int i=0; while(*p!= '/0' && *p== ' ') p++;//滤掉s1左端空格 if(*p== '/0') {printf("字符串s1为空串或空格串/n");exit(0); } while( *p!='/0' && i0) s[j++]=stk[i--] //将第偶数个字符逆序填入原字符数组 } 14.[题目分析]本题是对字符串表达式的处理问题,首先定义4种数据结构:符号的类码,符号的TOKEN 表示,变量名表NAMEL和常量表CONSL。这四种数据结构均定义成结构体形式,数据部分用一维数组存储,同时用指针指出数据的个数。算法思想是从左到右扫描表达式,对读出的字符,先查出其符号类码:若是变量或常量,就到变量名表和常量表中去查是否已有,若无,则在相应表中增加之,并返回该字符在变量名表或常量表中的下标;若是操作符,则去查其符号类码。对读出的每个符号,均填写其TOKEN表。如此下去,直到表达式处理完毕。先定义各数据结构如下。 struct // 定义符号类别数据结构 {char data[7]; //符号 char code[7]; //符号类码 }TYPL; typedef struct //定义TOKEN的元素 {int typ; //符号码 int addr; //变量、常量在名字表中的地址 }cmp; struct {cmp data[50];//定义TOKEN表长度<50 int last; //表达式元素个数 }TOKEN; struct {char data[15]; //设变量个数小于15个 int last; //名字表变量个数 }NAMEL; struct {char data[15]; //设常量个数小于15个 int last; //常量个数 }CONSL; int operator(char cr) //查符号在类码表中的序号 {for(i=3;i<=6;i++) if(TYPL.data[i]==cr) return(i); } void PROCeString() //从键盘读入字符串表达式(以‘#’结束),输出其TOKEN表示。 {NAMEL.last=CONSL.last=TOKEN.last=0; //各表元素个数初始化为0 TYPL.data[3]=‘*’;TYPL.data[4]=‘+’;TYPL.data[5]=‘(’; TYPL.data[6]=‘)’; //将操作符存入数组 TYPL.code[3]=‘3’;TYPL.code[4]=‘4’;TYPL.code[5]=‘5’; TYPL.code[6]=‘6’; //将符号的类码存入数组 scanf(“%c”,&ch); //从左到右扫描(读入)表达式。 while(ch!=‘#’) //‘#’是表达式结束符 {switch(ch)of {case‘A’: case ‘B’: case ‘C’: //ch是变量 TY=0; //变量类码为0 for(i=1;i<=NAMEL.last;i++) if(NAMEL.data[i]==ch)break;//已有该变量,i记住其位置 if(i>NAMEL.last){NAMEL.data[i]=ch;NAMEL.last++;}//变量加入 case‘0’: case‘1’: case‘2’: case‘3’: case‘4’: case‘5’://处理常量 case‘6’: case ‘7’:case‘8’: case‘9’: TY=1;//常量类码为1    for(i=1;i<=CONSL.last;i++) if(CONSL.data[i]==ch)break;////已有该常量,i记住其位置   if(i>CONSL.last){CONSL.data[i]=ch;CONSL.last++;}//将新常量加入  default: //处理运算符   TY=operator(ch);//类码序号   i=’/0’; //填入TOKEN的addr域(期望输出空白) }//结束switch,下面将ch填入TOKEN表 TOKEN.data[++TOKEN.last].typ=TY;TOKEN.data[TOKEN.last].addr=i; scanf(“%c”,&ch); //读入表达式的下一符号。 }//while }//算法结束 [程序讨论]为便于讨论,各一维数组下标均以1开始,在字符为变量或常量的情况下,将其类码用TY记下,用i记下其NAMEL表或CONSL表中的位置,以便在填TOKEN表时用。在运算符(‘+’,‘*’,‘(’,‘)’)填入TOKEN表时,TOKEN表的addr域没意义,为了程序统一,这里填入了’/0’。本题是表达式处理的简化情况(只有3个单字母变量,常量只有0..9,操作符只4个),若是真实情况,所用数据结构要相应变化。
原创粉丝点击