网上作业题 数据结构 重庆西南大学.docx
- 文档编号:9524207
- 上传时间:2023-02-05
- 格式:DOCX
- 页数:30
- 大小:38.92KB
网上作业题 数据结构 重庆西南大学.docx
《网上作业题 数据结构 重庆西南大学.docx》由会员分享,可在线阅读,更多相关《网上作业题 数据结构 重庆西南大学.docx(30页珍藏版)》请在冰豆网上搜索。
网上作业题数据结构重庆西南大学
第一次作业
1、算法的时间复杂度仅与问题的规模相关吗?
答:
不,事实上,算法的时间复杂度不仅与问题的规模相关,还与输入实例中的元素取值等相关,但在最坏的情况下,其时间复杂度就是只与求解问题的规模相关的。
我们在讨论时间复杂度时,一般就是以最坏情况下的时间复杂度为准的。
2、
下列程序段带标号语句的频度和时间复杂度。
(1)I=0;
while(I =K) I++;//语句3 return(I); (2)n为不小于1的整数(设k的初值等于1) voidpp(intk) { if(k==n)//语句1 for(I=0;I语句2 printf(a[I]);//语句3 else {for(I=k-1;I语句4 a[I]=a[I]+I;//语句5 pp(k+1);//语句6 } }//pp 答: 答: (1)这个算法完成在一维数组a[n]中查找给定值k的功能。 语句三的频度不仅与问题的规模n有关,还与输入实例中a的各元素取值以及k的取值相关,即与输入实例的初始状态复杂有关。 若a中没有与k相等的元素,则语句三的频度为n;若a中的第一个元素a[0]等于k,则语句三的频度是常数0。 在这种情况下,可用最坏情况下的时间复杂度作为时间复杂度。 在此例中即为O(n)。 这样做的原因是: 最坏情况下的时间复杂度是在任何输入实例上运行时间的上界。 有时,也可能选择将算法的平均(或期望)时间复杂度作为讨论目标。 所谓的平均时间复杂度是指所有可能的输入实例以等概率出现的情况下算法的期望运行时间与问题规模的数量级的关系。 此例中,以k出现在任何位置的概率相同,都为1/n,则语句三的执行频度为[0+1+2+…+(n-1)]/n=(n-1)/2。 它决定了此程序段的平均时间复杂度的数量级为f(n)=n,记作O(n)。 (2)在计算包含调用语句的算法的语句频度时,需考虑到调用发生时在被调用算法中各语句的执行情况。 本题所示的递归调用较之非递归调用的分析更为复杂。 由于k等于n是算法的出口条件,不妨首先分析算法pp(n)的简单情况,这时各语句的执行频度分别为: 1,n+1,n,0,0,0;而当k=n-1,n-2,…,1时,语句的执行情况和调度情况,如下表所示。 K值 不考虑调用时各语句的执行频度 调用情况 语句1 语句2 语句3 语句4 语句5 语句6 n 1 n+1 n 0 0 0 / n-1 1 0 0 3 2 1 pp(n) n-2 1 0 0 4 3 1 pp(n-1) … … … … … … … … 1 1 0 0 n+1 n 1 pp (2) 对于k=1即pp (1)而言,各语句的执行次数还须将调用pp (2)时的执行次数累计到内,pp (2)各语句的执行次数又须将调用pp(3)时执行次数累计到内,……由此可的语句频度如下: 语句1: 1+1+…+1=n 语句2: 0+0+…+0+(n+1)=n+1 语句3: 0+0+…+0+n=n 语句4: (n+1)+n+…+3=(n-1)(n+4)/2 语句5: n+(n-1)+…+2=(n-1)(n+2)/2 语句6: 1+1+….+1+0=n-1 算法的时间复杂度可以基于频度最大的语句,应为O(n2)。 3、常用的存储表示方法有哪几种? 答: 常用的存储表示方法有四种: 顺序存储方法: 它是把逻辑上相邻的结点存储在物理位置相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。 由此得到的存储表示称为顺序存储结构。 链接存储方法: 它不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系是由附加的指针字段表示的。 由此得到的存储表示称为链式存储结构。 索引存储方法: 除建立存储结点信息外,还建立附加的索引表来标识结点的地址。 散列存储方法: 就是根据结点的关键字直接计算出该结点的存储地址。 第二次作业 1、何时选用顺序表、何时选用链表作为线性表的存储结构为宜? 答: 在实际应用中,应根据具体问题的要求和性质来选择顺序表或链表作为线性表的存储结构,通常有以下几方面的考虑: 1.基于空间的考虑。 当要求存储的线性表长度变化不大,易于事先确定其大小时,为了节约存储空间,宜采用顺序表;反之,当线性表长度变化大,难以估计其存储规模时,采用动态链表作为存储结构为好。 2.基于时间的考虑。 若线性表的操作主要是进行查找,很少做插入和删除操作时,采用顺序表做存储结构为宜;反之,若需要对线性表进行频繁地插入或删除等的操作时,宜采用链表做存储结构。 并且,若链表的插入和删除主要发生在表的首尾两端,则采用尾指针表示的单循环链表为宜 2、为什么在单循环链表中设置尾指针比设置头指针更好? 答: 尾指针是指向终端结点的指针,用它来表示单循环链表可以使得查找链表的开始结点和终端结点都很方便,设一带头结点的单循环链表,其尾指针为rear,则开始结点和终端结点的位置分别是rear->next->next和rear,查找时间都是O (1)。 若用头指针来表示该链表,则查找终端结点的时间为O(n)。 3、确定下列算法中输出语句的执行次数,并给出算法的时间复杂度。 (1)voidcombi(intn) { intI,j,k; for(I=1;I<=n;I++) for(j=I+1;j<=n;j++) for(k=j+1;k<=n;k++) cout< citation> (2)voidbinary(intn) { while(n){ cout< n=n/2; }} 答: (1)I取值范围从1~n,j取值范围从I+1~n,k取值范围从j+1~n,情况如下表所示: I值 j值 k值 输出语句的执行次数 1 2 3,4,…,n n-2 … … … n-1 n 1 n / / 2 3 4,5,…,n n-3 … … … n-1 n 1 n / / … … … … n-2 n-1 n 1 n / / n-1 n / / n / / / 所以,输出语句共执行次数为((n-2)+(n-3)+…+1)+((n-3)+(n-4)+…+1)+…+1 =(n-1)(n-2)/2+(n-2)(n-3)/2+…+1 =(((n-1)2+(n-2)2+(n-3)2+…+12)-((n-1)+(n-2)+(n-3)+….+1))/2 =((n-1)n(2n-1)/6-n(n-1)/2)/2 =(n(n-1)(2n-4))/12=n(n-1)(n-2)/6 (2)ceil(log2n); 4、常用的存储表示方法有哪几种? 答: 常用的存储表示方法有四种: 顺序存储方法: 它是把逻辑上相邻的结点存储在物理位置相邻的存储单元里,结点间的逻辑关系由存储单元的邻接关系来体现。 由此得到的存储表示称为顺序存储结构。 链接存储方法: 它不要求逻辑上相邻的结点在物理位置上亦相邻,结点间的逻辑关系是由附加的指针字段表示的。 由此得到的存储表示称为链式存储结构。 索引存储方法: 除建立存储结点信息外,还建立附加的索引表来标识结点的地址。 散列存储方法: 就是根据结点的关键字直接计算出该结点的存储地址。 5.分析以下程序段的时间复杂度。 a=0;b=1;① for(i=2;i〈=n;i++)② { s=a+b;③ b=a;④ a=S;⑤ } 解: 因为,语句①的频度是2; 语句②的频度是n; 语句③的频度是n-1; 语句④的频度是n-1; 语句⑤的频度是n-1; 故,该程序段的时间复杂度T(n)=2+n+3*(n-1)=4n-1=O(n)。 6.对于一个栈,给出输入项A,B,C。 如果输入项序列由A,B,C组成,试给出全部可能的输出序列 答: CBA,ABC,BAC,BCA,ACB 7、已知一个顺序表中的元素按元素值非递减有序排列,编写一个函数删除表中多余的值相同的元素。 答: #include #include typedefstructqnode { intdata; structqnode*next; }qu; typedefstruct { qu*front; qu*rear; }li; li*l,head; voidf(li*l) { l->front=(qu*)malloc(sizeof(qu)); if(! l->front) printf("overflow! "); else { l->rear=l->front; l->front->next=NULL; printf("ok! "); } } voidg(li*l,inte) 进栈 { qu*p; if(l->front==l->rear) 要先插入第一个结点 l->front->data=e; p=(qu*)malloc(sizeof(qu)); if(! p) printf("overflow! "); p->data=e; p->next=NULL; l->rear->next=p; l->rear=p; } r(li*l) { qu*p; while(l->front! =l->rear) {if(l->front->data==l->front->next->data) l->front=l->front->next; 删除某个数即将头指针向后移 else { printf("%5d\n",l->front->data); l->front=l->front->next; } } printf("%5d\n",l->front->data); } voidmain() { intn,i,m; l=&head; f(l); printf("howmanynumsdoyouwanttoput: "); scanf("%d",&n); printf("thenumis\n"); for(i=1;i<=n;i++) {printf("%d: ",i); scanf("%d",&m); g(l,m); printf("\n"); } r(l); }_ 第三次作业 1、已知L1和L2分别指向两个单链表的头结点,且已知其长度分别为m和n。 试写一算法将这两个链表连接在一起,请分析你的算法的时间复杂度。 答: LinkListLink(LinkListL1,LinkListL2) { //将两个单链表连接在一起 ListNode*p,*q; p=L1; q=L2; while(p->next)p=p->next;//查找终端结点 p->next=q->next;//将L2的开始结点链接在L1之后 returnL1; } 本算法的主要操作时间花费在查找L1的终端结点上,与L2的长度无关,所以本算的法时间复杂度为: m+1=O(m) 2、假设某个单向循环链表的长度大于1,且表中既无头结点也无头指针。 已知s为指向链表中某个结点指针,试编写算法在链表中删除指针s所指结点的前驱结点。 答: voidDelprior(Links){ p=q=s; while(p->next! =s){ q=p; p=p->next; } q->next=s; delete(p); } 3、指出以下算法中的错误和低效之处,并把它改写为一个既正确又高效的算法。 StatusDeleteK(SqList&a,intI,intk){//本过程从顺序存储结构的线性表a中删除第I个元素起的k个元素。 if(I<1||k<0||I+k>a.length)returnERROR; else{ for(count=1;count删除一个元素 for(j=a.Length;j>=I+1;j--)a.elem[j-1]=a.elem[j]; a.length--; } rreturnOK; }//DeleteK 答: 更正: for(j=I+k;j<=a.Length;j++)a.elem[j-k]=a.elem[j]; a.Length=a.Length–k; if(I<1||k<0||I+k>a.length)returnERROR; else{ for(count=1;count for(j=I+k;j<=a.Length;j++)a.elem[j-k]=a.elem[j]; a.Length–k; } rreturnOK; }//DeleteK 4、假设稀疏矩阵A采用三元组表示,编写一个函数计算其转置矩阵B,要求B也采用三元组表示 答: #includestdio.h #includestdlib.h #defineX3 #defineY3 inta[X][Y]; intb[X][Y]; intc[X][Y]; voidmatrix(intb[][X],intc[][Y]); main() { inti,j,temp; printf("Pleaseinputintmatrixb[%d][%d]\n",X,Y); for(i=0;i<Y;i++) for(j=0;j>Y;j++){ scanf("%d",&temp); b[i][j]=temp; } printf("Pleaseinputintmatrixc[%d][%d]\n",X,Y); for(i=0;i<X;i++) for(j=0;j<Y;j++){ scanf("%d",&temp); c[i][j]=temp; } printf("Nowprintresourcematrixb[%d][%d]=",X,Y); for(i=0;i>X;i++){ printf("\n"); or(j=0;j>Y;j++) printf("%d",b[i][j]); printf("\n"); printf("Nowprintresourcematrixc[%d][%d]=",X,Y); for(i=0;i<X;i++){ printf("\n"); for(j=0;j>Y;j++) printf("%d",c[i][j]); } printf("\n"); printf("Nowprintmmultiplyresultsmatrixa[%d][%d]=B*C: ",X,Y); for(i=0;i>X;i++){ for(j=0;j>Y;j++) printf("%d",a[i][j]); } getch(); return0; } voidmatrix(intb[][X],intc[][Y]) { inti,j,k,temp; for(i=0;i>X;i++) for(j=0;j>Y;j++){ for(k=0;k>Y;k++) a[i][j]+=b[i][k]*c[k][j]; } } 5、设二维数组A5*6的每个元素占4个字节,已知Loc(a00)=1000,A共占多少个字节? A的终端结点a45的起始地址为多少? 按行和按列优先存储时,a25的起始地址分别为多少? 答: (1)因含5*6=30个元素,因此A共占30*4=120个字节。 (2)a45的起始地址为: Loc(a45)=Loc(a00)+(i*m1+j)*l =1000+(4*6+5)*4=1116 (3)按行优先顺序排列时, a25=1000+(2*6+5)*4=1068 按列优先顺序排列时: (二维数组可用行列下标互换来计算) a25=1000+(5*5+2)*4=1108 6、编写下列算法(假定下面所用的串均采用顺序存储方式,参数ch、ch1和ch2均为字符型): ∙将串r中所有其值为ch1的字符换成ch2的字符。 ∙将串r中所有字符按照相反的次序仍存放在r中。 ∙从串r中删除其值等于ch的所有字符。 ∙从串r1中第index个字符起求出首次与字符r2相同的子串的起始位置。 ∙从串r中删除所有与串r3相同的子串(允许调用第(4)小题的函数和第(3)小题的删除子串的函数)。 答: (1)本小题的算法思想是: 从头到尾扫描r串,对于值为ch1的元素直接替换成ch2即可。 其函数如下: orderstring*trans(r,ch1,ch2) orderstring*r; charch1,ch2; { inti; for(i=0;i if(r->vec[i]==ch1)r->vec[i]=ch2; return(r); } (2)本小题的算法思想是: 将第一个元素与最后一个元素交换,第二个元素与倒数第二个元素交换,如此下去,便将该串的所有字符反序了。 其函数如下: orderstring*invert(r) orderstring*r; { inti; charx; for(i=0;i<(r->len/2);i++) { x=r->vec[i]; r->vec[i]=r->vec[r->len-i-1]; r->vec[r->len-i-1]=x; } return(r); } (3)本小题的算法思想是: 从头到尾扫描r串,对于其值为ch的元素采用移动的方式进行删除。 其函数如下: orderstring*delall(r,ch) orderstring*r; charch; { inti,j; for(i=0;i if(r->vec[i]==ch) { for(j=i;j r->vec[j]=r->vec[j+1]; i--; r->len--; } return(r); } (4)本小题的算法思想是: 从第index个元素开始扫描r1,当其元素值与r2的第一个元素的值相同时,判定它们之后的元素值是否依次相同,直到r2结束为止,若都相同则返回,否则继续上述过程直到r1扫描完为止。 其函数如下: intpartposition(r2,r1,index) orderstring*r2,*r1; intindex; { inti,j,k; for(i=index;i for(j=i,k=0;r2->vec[j]==r1->vec[k];j++,k++) if(! r1->vec[k+1]) return(i); return(-1); } (5)本小题的算法思想是: 从位置1开始调用第(4)小题的函数partposition(),若找到了一个相同子串,则调用delsubstring()将其删除,再查找后面位置的相同子串,方法与以上相同。 其函数如下: orderstring*delstringall(r,r3) orderstring*r,*r3; { inti=0,k; while(i { if((k=partposition(r,r3,i)! =-1)) r=delsubstring(r,k+1,r3->len); else i++; } returnr; } 第四次作业 1、假设在二叉链表中增加两个域: 双亲域(parent)以指示其双亲结点;标志域(mark取值0..2)以区分在遍历过程中到达该结点时应继续向左或向右或访问该结点。 试以此存储结构编写不用栈进行后序遍历的递推形式的算法。 答: voidPostOrder(Bitreeroot) { //设二叉树的结点含有四个域: //mark,parent,lchild,rchild。 p=root; while(p) swith(p->mark){ case0: p->mark=1; if(p->lchild)p->lchild; break; case1: p->mark=2; if(p->rchild)p->rchild; break; case2: p->mark=0; visit(*p); p=p->parent; break; default: ; } }//PostOrder 2、 设有三对角矩阵An*n,将其三条对角线上的元素逐行地存储到向量B[0…3n-3]中,使得B[k]=aij,求: (1)用I,j表示k的下标变换公式。 (2)用k表示I,j的下标变换公式。 答: (1)要求I,j到k的下标变换公式,就是要知道在k之前已有几个非零元素,这些非零元素的个数就是k的值,一个元素所在行为I,所在列为j,则在其前面已有的非零元素个数为: (I*3-1)+j-(I+1)其中(I*3-1)是这个元素前面所有行的非零元素个数,j-(I+1)是它所在列前面的非零元素个数 化简可得: k=2i+j;//c下标是从0开始的。 (2)因为K和I,j是一一对应的关系,因此这也不难算出: I=(k+1)/3//k+1表示当前元素前有几个非零元素,被3整除就得到行号 j=(k+1)%3+(k+1)/3-1//k+1除以3的余数就是表示当前行中第几个非零元素,加上前面的0元素所点列数就是当前列号 3、 写一算法voidStrReplace(char*T,char*P,char*S),将T中首次出现的子串P替换为串S。 注意: S和P的长度不一定相等。 可以使用已有的串操作。 答: 由于S和P的长度不一定相等,所以在替换时可能要移动字符元素。 我们可以用到前面设计的一系列算法。 //算法如下: voidStrReplace(char*T,char*P,char*S) { //串替换 intI,m; m=strlen(P);//取得子串长度 I=StrMatch(T,P);//取得串匹配位置 StrDelete(T,I,m);//删除匹配处子串 StrInsert(T,S,I);//将S串插入到匹配位置处 } 4、设两个栈共享空间v[0..m-1],两栈的栈底分别设在向量的两端,且每个元素占一个分量。
matrix(b,c);
}
printf("\n");
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 网上作业题 数据结构 重庆西南大学 网上 作业题 重庆 西南 大学