习题讲评二共14页.docx
《习题讲评二共14页.docx》由会员分享,可在线阅读,更多相关《习题讲评二共14页.docx(7页珍藏版)》请在冰豆网上搜索。
习题讲评二共14页
第二章线性表
P18—P20
2.32、2.39、2.41
2.32②已知有一个单向循环链表,其每一个结点中含三个域:
pre,data和next,其中data为数据域,next为指向后继结点的指针域,pre也为指针域,但它的值为空(NULL),试编写算法将此单向循环链表改为双向循环链表,即使pre成为指向前驱结点的指针域。
StatusDuLNode_Pre(DuLinkList&L)//完成双向循环链表结点的pre域
{
for(p=L;p->next->pre==NULL;p=p->next)
p->next->pre=p;
returnOK;
}//DuLNode_Pre
2.39③已知稀疏多项式Pn(X)=c1xe1+c2xe2+…+cmxem其中n=em>em-1>…….>e1>=0,ci≠0(i=1,2,…m),m≥1。
试采用存储同多项式数m成正比的顺序存储结构,编写求Pn(x0)的算法(x0为给定值),并分析你的算法的时间复杂度。
typedefstruct{
floatcoef;//系数;
intexp;//指数;
}PolyTerm;
typedefstruct{
PolyTerm*data;
intlength;
intlistsize;
}SqPoly;//类似顺序表中结构体的定义;
floatGetValue_SqPoly(SqPolyP,intx0)//求升幂顺序存储的稀疏多项式的值
{
PolyTerm*q;
xp=1;
q=P.data;
sum=0;
while(q->coef)//系数;
{
ex=0;
while(exexp){
xp*=x0;
ex++;
}
sum+=q->coef*xp;
q++;
}
returnsum;
}//GetValue_SqPoly
时间复杂度:
n2
2.41②试以循环链表作为稀疏多项式的存储结构,编写求其导函数的算法,要求利用原多项式中的结点空间存放其导函数(多项式),同时释放所有无用(被删)结点。
voidQiuDao_LinkedPoly(LinkedPoly&L)//对有头结点循环链表结构存储的稀疏多项式L求导
{
p=L->next;
if(!
p->data.exp)//跳过常数项
{
L->next=p->next;
p=p->next;
}
while(p!
=L)//循环链表;
{
p->data.coef*=p->data.exp;//对每一项求导
p->data.exp--;
p=p->next;
}
}//QiuDao_LinkedPoly
cmxem的导数为:
cmemxem-1
第三章栈和队列
3.173.253.313.323.33
3.17③试写一个算法,识别依次读入的一个以@为结束符的字符序列是否为形如‘序列1&序列2’模式的字符序列。
其中序列1和序列2中不包含字符’&’,且序列2是序列1的逆序列。
例如,‘a+b&b+a’是属于该模式的字符序列,而‘1+2&2-1’则不是。
intIsReverse()
//判断输入的字符串中'&'前和'&'后部分是否为逆串,是则返回1,否则返回0
{
InitStack(s);
while((e=getchar())!
='&')
push(s,e);
while((e=getchar())!
='@')
{
if(StackEmpty(s))return0;
pop(s,c);
if(e!
=c)return0;
}
if(!
StackEmpty(s))return0;//判断栈中是否还有元素;
return1;
}//IsReverse
3.25④试写出递归函数F(n)的递归算法,并消除递归:
F(n)=n+1,n=0;F(n)=n*F(n/2),n>0
StatusF_recursive(intn,int&s)//递归算法;s为返回值;
{
if(n<0)returnERROR;
if(n==0)s=n+1;
else
{
F_recurve(n/2,r);
s=n*r;
}
returnOK;
}//F_recursive
StatusF_nonrecursive(intn,ints)//非递归算法
{
if(n<0)returnERROR;
if(n==0)s=n+1;
else
{
InitStack(s);//s的元素类型为struct{inta;intb;}
while(n!
=0)
{
a=n;b=n/2;
push(s,{a,b});
n=b;
}//while
sum=1;
while(!
StackEmpty(s))
{
pop(s,t);
sum*=t.a;
}//while
}
returnOK;
}//F_nonrecursive
3.31③假设称正读和反读都相同的字符序列为“回文”,例如,‘abba’和‘abcba’是回文,‘bcde’和‘ababa’则不是回文,试写一个算法判别读入的一个以‘@’为结束符的字符序列是否是“回文”。
栈:
后进先出;
队列:
先进先出;
intPalindrome_Test()//判别输入的字符串是否回文序列,是则返回1,否则返回0
{
InitStack(S);//初始化栈;
InitQueue(Q);//初始化队列;
while((c=getchar()!
='@')
{
Push(S,c);//入栈;
EnQueue(Q,c);//入队列;
}
while(!
StackEmpty(S))
{
Pop(S,a);//出栈;
DeQueue(Q,b));//出队列;
if(a!
=b)returnERROR;
}
returnOK;//若是回文,则返回OK;
}//Palindrome_Test
3.32④试利用循环队列编写求k阶斐波那契序列中前n+1项,(f0,f1,….fn)的算法,要求满足:
fn≤max而fn+1>max,其中max为某个约定的常数。
(注意:
本题所用循环队列的容量仅为k,则在算法执行结束时,留在循环队列中的元素应是所求k阶斐波那契序列中的最后k项fn-k+1,….fn)。
voidGetFib_CyQueue(intk,intmax)//求k阶斐波那契序列的前n+1项
{
InitCyQueue(Q);//其MAXSIZE设置为k
for(i=0;i Q.base[k-1]=1;//给前k项赋初值0,…,0,1
for(i=0;iflag=0;//设置标志;
for(i=k;flag==0;i++)
{
m=i%k;sum=0;
for(j=0;jif(sum<=max)
{
Q.base[m]=sum;//求第i项的值存入队列中并取代已无用的第一项
printf("%d",sum);//要求满足:
fn≤max而fn+1>max;
}
elseflag=1;//退出循环;
}
}//GetFib_CyQueue
3.33③在顺序存储结构上实现输出受限的双端循环队列的入列和出列(只允许队头出列)算法。
设每个元素表示一个待处理的作业,元素值表示作业的预计时间。
入队列采取简化的短作业优先原则,若一个新提交的作业的预计执行时间小于队头和队尾作业的平均时间,则插入在队头,否则插入在队尾。
双端循环队列:
两端都可以进行入列和出列操作。
输出受限的双端循环队列:
队头可以入列和出列,队尾只能入列。
rear指向最后一个元素的下一个位置;front指向第一个元素;
StatusEnDQueue(DQueue&Q,intx)//输出受限的双端队列的入队操作
{
if((Q.rear+1)%MAXSIZE==Q.front)returnOVERFLOW;//队列满;牺牲一个结点;
avr=(Q.base[Q.rear-1]+Q.base[Q.front])/2;//队头和队尾作业的平均时间;
if(x>=avr)//插入队尾
{
Q.base[Q.rear]=x;
Q.rear=(Q.rear+1)%MAXSIZE;//rear指向最后一个元素的下一个位置;
}
else
{
Q.front=(Q.front-1)%MAXSIZE;//front下移一位;
Q.base[Q.front]=x;//front指向第一个元素;
}//插入在队头
returnOK;
}//EnDQueue
StatusDeDQueue(DQueue&Q,int&x)//输出受限的双端队列的出队操作
{//只能在队头出列,队尾不允许出列;
if(Q.front==Q.rear)returnERROR;//队列空;
x=Q.base[Q.front];
Q.front=(Q.front+1)%MAXSIZE;
returnOK;
}//DeDQueue
第四章串
串赋值StrAssign、串复制Strcopy、串比较StrCompare、求串长StrLength、串联接Concat以及求子串SubString等六种操作构成串类型的最小操作子集。
这些操作不可能利用其他串操作来实现,反之,其他串操作(除串清除ClearString和串销毁DestroyString外)可在这个最小操作子集上实现。
StrAssign(&T,chars)//串赋值
初始条件:
chars是字符串常量。
操作结果:
把chars赋为T的值。
StrCopy(&T,S)//串复制
初始条件:
串S存在。
操作结果:
由串S复制得串T。
利用最小操作子集中的操作也可实现
串判空StrEmpty(S)、串替换Replace(&S,T,V)、串删除StrDelete(&S,pos,len)、串插入StrInsert(&S,pos,T)等操作。
串判空:
intStrEmpty(StringS){
if(!
StrLength(S))
returnTRUE;//为空;
elsereturnFALSE;//不为空;
}
串替换:
初始条件:
串S,T和V均已存在,且T是非空串。
操作结果:
用V替换主串S中出现的所有与(模式串)T相等的不重叠的子串。
intReplace(String&S,StringT,StringV);//将串S中所有子串T替换为V,并返回置换次数
{
for(n=0,i=1;i<=Strlen(S)-Strlen(T)+1;i++)//注意i的取值范围
if(!
StrCompare(SubString(S,i,Strlen(T)),T))//找到了与T匹配的子串
{//分别把T的前面和后面部分保存为head和tail;
Strcopy(head,SubString(S,1,i-1));
Strcopy(tail,SubString(S,i+Strlen(T),Strlen(S)-i-Strlen(T)+1));
Strcopy(S,Concat(head,V));
Strcopy(S,Concat(S,tail));//把head,V,tail连接为新串
i+=Strlen(V);//当前指针跳到插入串以后
n++;
}//if
returnn;
}//Replace
分析:
i+=Strlen(V);这一句是必需的,也是容易忽略的.如省掉这一句,则在某些情况下,会引起不希望的后果,虽然在大多数情况下没有影响.请思考:
设S='place',T='ace',V='face',则省掉i+=Strlen(V);运行时会出现什么结果?
串删除:
intStrDelete(String&S,intpos,intlen){
if(1≤pos≤StrLength(S)-len+1)
{
Strcopy(head,SubString(S,1,pos-1));
Strcopy(tail,SubString(S,pos+len,Strlen(S)-pos-len+1));
Strcopy(S,Concat(head,tail)); //把head,tail连接为新串
returnOK;
}
elsereturnERROR;
}//StrDelete
串插入:
初始条件:
串S和T存在,1≤pos≤StrLength(S)+1。
操作结果:
在串S的第pos个字符之前插入串T。
intStrInsert(String&S,intpos,StringT);
{
if(1≤pos≤StrLength(S)+1)
{
Strcopy(head,SubString(S,1,pos-1));
Strcopy(tail,SubString(S,pos,Strlen(S)-pos+1));
Strcopy(S,Concat(head,T));
Strcopy(S,Concat(S,tail));//把head,T,tail连接为新串
returnOK;
}
elsereturnERROR;
}//StrInsert
希望以上资料对你有所帮助,附励志名言3条:
1、理想的路总是为有信心的人预备着。
2、最可怕的敌人,就是没有坚强的信念。
——罗曼·罗兰
3、人生就像爬坡,要一步一步来。
——丁玲