c[k++]=a[l];
returnk;/*返回c的长度*/
}
2.2.2综合题9、
有一个单链表(不同结点的数据域值可能相同),其头指针为head,编写一个函数计算数据域为x的结点个数。
解:
本题是遍历通过该链表的每个结点,每遇到一个结点,结点个数加1,结点个数存储在变量n中。
实现本题功能的函数如下:
intcount(head,x)
node*head;
ElemTypex;
{
node*p;
intn=0;
p=head;
while(p!
=NULL)
{
if(p->data==x)n++;
p=p->next;
}
return(n);
}
2.2.2综合题11、
有一个单链表L(至少有1个结点),其头结点指针为head,编写一个函数将L逆置,即最后一个结点变成第一个结点,原来倒数第二个结点变成第二个结点,如此等等。
解:
本题采用的算法是:
从头到尾扫描单链表L,将第一个结点的next域置为NULL,
将第二个结点的next域指向第一个结点,将第三个结点的next域指向第二个结点,如此等等,直到最后一个结点,便用head指向它,这样达到了本题的要求。
实现本题功能的函数如下:
voidinvert(head)
node*head;
{
node*p,*q,*r;
p=head;
q=p->next;
while(q!
=NULL)/*当L没有后续结点时终止*/
{r=q->next;
q->next=p;
p=q;
q=r;
}head->next=NULL;
head=p;/*p指向L的最后一个结点,现改为头结点*/
}
2.2.2综合题16、
有一个有序单链表(从小到大排列),表头指针为head,编写一个函数向该单链表中插入一个元素为x的结点,使插入后该链表仍然有序。
解:
本题算法的思想是先建立一个待插入的结点,然后依次与链表中的各结点的数据域比较大小,找到插入该结点的位置,最后插入该结点。
实现本题功能的函数如下:
node*insertorder(head,x)
node*head;ElemTypex;
{
node*s,*p,*q;
s=(node*)malloc(sizeof(node));/*建立一个待插入的结点*/
s->data=x;
s->next=NULL;
if(head==NULL||xdata)/*若单链表为空或x小于第一个结点的date域*/
{
s->next=head;/*则把s结点插入到表头后面*/
head=s;
}
else
{q=head;/*为s结点寻找插入位置,p指向待比较的结点,q指向p的前驱结点*/
p=q->next;
while(p!
=NULL&&x>p->data)/*若x小于p所指结点的data域值*/
if(x>p->data)/*则退出while循环*/
{
q=p;
p=p->next;
}
s->next=p;/*将s结点插入到q和p之间*/
q->next=s;
}
return(head);
}
2.2.2综合题23、
假设在长度大于1的循环单链表中,既无头结点也无头指针,p为指向该链表中某个结点的指针,编写一个函数删除该结点的前驱结点。
解:
本题利用循环单链表的特点,通过p指针可循环找到其前驱结点q及q的前驱结点r,然后将其删除。
实现本题功能的函数如下:
node*del(p)
node*p;
{
node*q,*r;
q=p;/*查找p结点的前驱结点,用q指针指向*/
while(q->next!
=p)q=q->next;
r=q;/*查找q结点的前驱结点,用r指针指向*/
while(r->next!
=q)r=r->next;
r->next=p;/*删除q所指的结点*/
free(q);
return(p);
}
2.2.2综合题41
试写一算法在带头结点的单链表结构上的实现线性表操作LOCATE(L,X)。
LNode*Locate(LinkListL,intx)//链表上的元素查找,返回指针
{
for(p=l->next;p&&p->data!
=x;p=p->next);
returnp;
}//Locate
第三章栈和队列
3.2.2综合习题13、
如果用一个循环数组qu[0,m0-1]表示队列时,该队列只有一个头指针front,不设队尾指针rear,而改置计数器count用以记录队列中结点的个数。
(1)编写实现队列的五个基本运算;
(2)队列中能容纳元素的最多个数还是m0-1吗?
解:
(1)依题意,有如下条件:
队列为空:
count==0,front==1
队列为满:
count==m0
队列尾的第一个元素位置==(front+count)%m0
队列首的第一个元素位置==(front+1)%m0
队列类型定义如下:
typedefintqu[m0];
由此得到如下对应上述基本运算的5个函数如下:
/*m0定义为全局变量*/
voidmakenull(front,count)/*使队列q为空*/
intfront,count;
{front=1;count=0;}
intempty(count)/*判定队列q是否为空*/
intcount;
{if(count==0)return
(1);elsereturn(0);}
voidpop(q,front,count,x)/*取队列头元素给x*/
quq;
intfront,count;
ElemType*x;
{
if(count==0)printf("队列下溢出\n");
else
{front=(front+1)%m0;*x=q[front];}
}
voidenqueue(q,x,front,count)/*将元素x入队列*/
quq;
intfront,count;
ElemTypex;
{intplace;
if(count==m0)printf("队列上溢出\n");
else
{count++;e=(front+count)%m0;q[place]=x;}
}
voiddequeue(q,front,count)/*删除队列头元素*/
quq;
intfront,count;
{
if(count==0)printf("队列下溢出\n");
else
{front=(front+1)%m0;count--;}
}
(2)队列中可容纳的最多元素个数为m0个。
3.2.2综合习题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;
}//Palindrome_Test
第三章串
4.2.3综合习题2、
若x和y是两个采用顺序结构存储的串,编写一个比较两个串是否相等的函数。
解:
两个串相等表示对应的字符必须都相同,所以扫描两串,逐一比较相应位置的字符,若相同继续比较直到全部比较完毕,如果都相同则表示两串相等,否则表示两串不相等,由此得到如下函数:
intsame(x,y)
orderstring*x,*y;
{
inti=0,tag=1;
if(x->len!
=y->len)
return(0);
else
{
while(ilen&&tag)
{
if(x->vec[i]!
=y->vec[i])tag=0;
i++;
}
return(tag);
}
}
4.2.3综合习题4、
采用顺序结构存储串s,编写一个函数删除s中第i个字符开始的j个字符。
解:
本题的算法思想是:
先判定s串中要删除的内容是否存在,若存在则将第i+j-1之后的字符前移j个位置。
其函数如下:
orderstring*delij(s,i,j)
orderstring*s;
inti,j;
{
inth;
if(i+jlen)
{
for(h=i;h
s->vec[h]=s->vec[h+j];
s->len-=j;
return(s);
}
elseprintf("无法进行删除操作\n");
}
4.2.3综合习题24、
编写算法,求串s所含不同字符的总数和每种字符的个数。
typedefstruct{
charch;
intnum;
}mytype;
voidStrAnalyze(StringtypeS)//统计串S中字符的种类和个数
{
mytypeT[MAXSIZE];//用结构数组T存储统计结果
for(i=1;i<=S[0];i++)
{
c=S[i];j=0;
while(T[j].ch&&T[j].ch!
=c)j++;//查找当前字符c是否已记录过
if(T[j].ch)T[j].num++;
elseT[j]={c,1};
}//for
for(j=0;T[j].ch;j++)
printf("%c:
%d\n",T[j].ch,T[j].num);
}//StrAnalyze
4.2.3综合习题30
试写一算法,在串的堆存储结构上实现基本操作Concat(&T,s1.s2).
voidHString_Concat(HStrings1,HStrings2,HString&t)//将堆结构表示的串s1和s2连接为新串t
{
if(t.ch)free(t.ch);
t.ch=malloc((s1.length+s2.length)*sizeof(char));
for(i=1;i<=s1.length;i++)t.ch[i-1]=s1.ch[i-1];
for(j=1;j<=s2.length;j++,i++)t.ch[i-1]=s2.ch[j-1];
t.length=s1.length+s2.length;
}//HString_Concat
第五章数组与广义表
5.2.3综合习题9、
假设稀疏矩阵A和B(具有相同的大小m×n)都采用三元组表示,编写一个函数计算C=A+B,要求C也采用三元组表示。
解:
本题采用的算法思想是:
依次扫描A和B的行号和列号,若A的当前项的行号等于B的当前项的行号,则比较其列号,将较小列的项存入C中,如果列号也相等,则将对应的元素值相加后存入C中;若A的当前项的行号小于B的当前项的行号,则将A的项存入C中;若A的当前项的行号大于B的当前项的行号,则将B的项存入C中。
这样产生了C,因此,实现本题功能的函数如下:
voidmatadd(A,B,C)
smatrikA,B,C;
{
inti=1,j=1,k=1;
while(i<=A[0][2]&&j<=B[0][2])
/*若A的当前项的行号等于B的当前项的行号,则比较其列号,将较小列的项*/
/*存入C中,如果列号也相等,则将对应的元素值相加后存入C中*/
if(A[i][0]==B[j][0])
if(A[i][1]
{
C[k][0]=A[i][0];
C[k][1]=A[i][1];
C[k][2]=A[i][2];
k++;
i++;
}
elseif(A[i][1]>B[j][1])
{
C[k][0]=B[j][0];
C[k][1]=B[j][1];
C[k][2]=B[j][2];
k++;
j++;
}
else
{
C[k][0]=B[j][0];
C[k][1]=B[j][1];
C[k][2]=A[i][2]+B[j][2];
if(C[k][2]!
=0)k++;
i++;
j++;
}
elseif(A[i][0]
/*若A的当前项的行号小于B的当前项的行号,则将A的项存入C中*/
{
C[k][0]=A[i][0];
C[k][1]=A[i][1];
C[k][2]=A[i][2];
k++;
i++;
}
else/*若A的当前项的行号大于B的当前项的行号,则将B的项存入C中*/
{
C[k][0]=B[j][0];
C[k][1]=B[j][1];
C[k][2]=B[j][2];
k++;
j++;
}
C[0][0]=A[0][0];/*产生第0行的结果*/
C[0][1]=A[0][1];
C[0][2]=k-1;
}
5.2.3综合习题26
试设计一个算法,将数组An中的元素A[0]至A[n-1]循环右移k位,并要求只用一个元素大小的附加存储,元素移动或交换次数为O(n)。
voidRSh(intA[n],intk)//把数组A的元素循环右移k位,只用一个辅助存储空间
{
for(i=1;i<=k;i++)
if(n%i==0&&k%i==0)p=i;//求n和k的最大公约数p
for(i=0;i
{
j=i;l=(i+k)%n;temp=A[i];
while(l!
=i)
{
A[j]=temp;
temp=A[l];
A[l]=A[j];
j=l;l=(j+k)%n;
}//循环右移一步
A[i]=temp;
}//for
}//RSh
分析:
要把A的元素循环右移k位,则A[0]移至A[k],A[k]移至A[2k]......直到最终回到A[0].然而这并没有全部解决问题,因为有可能有的元素在此过程中始终没有被访问过,而是被跳了过去.分析可知,当n和k的最大公约数为p时,只要分别以A[0],A[1],...A[p-1]为起点执行上述算法,就可以保证每一个元素都被且仅被右移一次,从而满足题目要求.也就是说,A的所有元素分别处在p个"循环链"上面.举例如下:
n=15,k=6,则p=3.
第一条链:
A[0]->A[6],A[6]->A[12],A[12]->A[3],A[3]->A[9],A[9]->A[0].
第二条链:
A[1]->A[7],A[7]->A[13],A[13]->A[4],A[4]->A[10],A[10]->A[1].
第三条链:
A[2]->A[8],A[8]->A[14],A[14]->A[5],A[5]->A[11],A[11]->