数据结构上机例题及答案.docx
《数据结构上机例题及答案.docx》由会员分享,可在线阅读,更多相关《数据结构上机例题及答案.docx(35页珍藏版)》请在冰豆网上搜索。
数据结构上机例题及答案
习题二
⒉1描述以下四个概念的区别:
头指针变量,头指针,头结点,首结点(第一个结点)。
解:
头指针变量和头指针是指向链表中第一个结点(头结点或首结点)的指针;在首结点之前附设一个结点称为头结点;首结点是指链表中存储线性表中第一个数据元素的结点。
若单链表中附设头结点,则不管线性表是否为空,头指针均不为空,否则表示空表的链表的头指针为空。
2.2简述线性表的两种存储结构有哪些主要优缺点及各自使用的场合。
解:
顺序存储是按索引直接存储数据元素,方便灵活,效率高,但插入、删除操作将引起元素移动,降低了效率;而链式存储的元素存储采用动态分配,利用率高,但须增设表示结点之间有序关系的指针域,存取数据元素不如顺序存储方便,但结点的插入和删除十分简单。
顺序存储适用于线性表中元素数量基本稳定,且很少进行插入和删除,但要求以最快的速度存取线性表中的元素的情况;而链式存储适用于频繁进行元素动态插入或删除操作的场合。
2.3在头结点为h的单链表中,把值为b的结点s插入到值为a的结点之前,若不存在a,就把结点s插入到表尾。
Voidinsert(Lnode*h,inta,intb)
{Lnode*p,*q,*s;
s=(Lnode*)malloc(sizeof(Lnode));
s->data=b;
p=h->next;
while(p->data!
=a&&p->next!
=NULL)
{q=p;
p=p->next;
}
if(p->data==a)
{q->next=s;
s->next=p;}
else
{p->next=s;
s->next=NULL;
}
}
2.4设计一个算法将一个带头结点的单链表A分解成两个带头结点的单链表A和B,使A中含有原链表中序号为奇数的元素,而B中含有原链表中序号为偶数的元素,并且保持元素原有的相对顺序。
Lnode*cf(Lnode*ha)
{Lnode*p,*q,*s,*hb;
intt;
p=ha->next;
q=ha;
t=0;
hb=(Lnode*)malloc(sizeof(Lnode));
s=hb;
while(p->next!
=NULL)
{if(t==0)
{q=p;p=p->next;t=1;}
else
{q->next=p->next;
p->next=s->next;s->next=p;s=p;
p=p->next;t=0;
}
}
s->next=NULL;
return(hb);
}
2.5设线性表中的数据元素是按值非递减有序排列的,试以不同的存储结构,编写一算法,将x插入到线性表的适当位置上,以保持线性表的有序性。
⑴顺序表;
解:
本题的算法思想是:
先找到适当的位置,然后后移元素空出一个位置,再将x插入,并返回向量的新长度。
实现本题功能的函数如下:
intinsert(vectorA,intn,ElemTypex)/*向量A的长度为n*/
{inti,j;
if(x>=A[n-1])A[n]=x/*若x大于最后的元素,则将其插入到最后*/else
{i=0;
while(x>=A[i])i++;/*查找插入位置i*/
for(j=n-1;j>=i;j--)A[j+1]=A[j];/*移出插入x的位置*/A[i]=x;
n++;/*将x插入,向量长度增1*/
}
returnn;
}
⑵单链表。
解:
本题算法的思想是先建立一个待插入的结点,然后依次与链表中的各结点的数据域比较大小,找到插入该结点的位置,最后插入该结点。
实现本题功能的函数如下:
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.6假设有A和B分别表示两个递增有序排列的线性表集合(即同一表中元素值各不相同),求A和B的交集C,表C中也依值递增有序排列。
试以不同的存储结构编写求得C的算法。
⑴顺序表;
voidSqList_Intersect_True(SqList&A,SqListB)//求元素递增排列的线性表A和B的元素的交集并存回A中
{
i=1;j=1;k=0;
while(A.elem[i]&&B.elem[j])
{
if(A.elem[i] elseif(A.elem[i]>B.elem[j])j++;
elseif(A.elem[i]!
=A.elem[k])
{
A.elem[++k]=A.elem[i];//当发现了一个在A,B中都存在的元素
i++;j++;//且C中没有,就添加到C中
}
}//while
while(A.elem[k])A.elem[k++]=0;
}//SqList_Intersect_True
⑵单链表。
单链表
chnode*or(chnode*head1,chnode*head2)
{chnode*p1,*p2,*q2,*h,*p;
h=p=malloc(sizeof(chnode));
p->next=NULL;
p1=head1->next;
while(p1)
{p2=head2;
q2=p2->next;
while((q2->data!
=p1->data)&&q2)
{p2=q2;
q2=q2->next;
}
if(p1->data==q2->data)
p2->next=q2->next;
if(q2)
{while(p->next)
p=p->next;
p->next=q2;
p=q2;
q2->next=NULL;
}
p1=p1->next;
}
return(h);
}
2.7设计一个算法求两个递增有序排列的线性表A和B的差集。
(每个单链表中不存在重复的元素)
提示:
即在A中而不在B中的结点的集合。
typedefintelemtype;
typedefstructlinknode
{
elemtypedata;
structlinknode*next;
}nodetype;
nodetype*subs(nodetype*heada,nodetype*headb)
{
nodetype*p,*q,*r,*s;
s=(nodetype*)malloc(sizeof(nodetype));
s->next=heada;
heada=s;
p=heada->next;
r=heada;r->next=NULL;
while(p!
=NULL)
{
q=headb;
while(q!
=NULL&&q->data!
=p->data)q=q->next;
if(q!
=NULL)
{
s=p->next;
free(p);p=s;
}
else
{
r->next=p;s=p->next;
r=p;r->next=NULL;
p=s;
}
}
s=heada;heada=heada->next;free(s);
returnheada;
}
2.8设有线性表A=(a1,a2,...,am),B=(b1,b2,...,bn)。
试写一合并A、B为线性表C的算法,使得
(a1,b1,...,am,bm,bm+1,...,bn)当m≤n时
C={
(a1,b1,...,an,bn,an+1,...,am)当m>n时
A、B和C均以单链表作存储结构,且C表利用A和B中结点空间。
解:
假设A,B和C链表分别具有头结点的指针a,b和c。
实现本题功能的函数如下:
node*link(a,b)
node*a,*b;
{
node*r,*s,*p,*q,*c;
c=(node*)malloc(sizeof(node));/*建立一个头结点*/
r=c;p=a;q=b;
while(p!
=NULL||q!
=NULL)
{
if(p!
=NULL)/*如果A链表还存在可取的结点,则复制一个同样的结点链接到C中*/
{
s=(node*)malloc(sizeof(node));
s->data=p->data;
r->next=s;
r=s;
p=p->next;
}
if(q!
=NULL)/*如果B链表还存在可取的结点,则复制一个同样的结点链接到C中*/
{
s=(node*)malloc(sizeof(node));
s->data=q->data;
r->next=s;
r=s;
q=q->next;
}
}
r->next=NULL;
s=c;
c=c->next;/*删除头结点*/
free(s);
return(c);
}
2.9试用两种线性表的存储结构来解决约瑟夫问题。
设有n个人围坐在圆桌周围,现从第s个人开始报数,数到第m个人出列,然后从出列的下一个人重新开始报数,数到第m个人又出列,…,如此重复直到所有的人全部出列为止。
例如当n=8,m=4,s=1,得到的新序列为:
4,8,5,2,1,3,7,6。
写出相应的求解算法。
解:
先构造一个循环链表
nodetype*crea(intn)
{nodetype*s,*r,*h;
intI;
for(i=1;i<=n;i++)
{s=(nodetype*)malloc(sizeof(nodetype));
s->data=I;s->next=NULL;
if(i==1)h=s;
elser->next=s;
r=s;
}
r->next=h;
returnh;
}
voidjese(nodetype*h,intm)
{nodetype*p=h,*q;
intI;
while(p->next!
=p)
{for(i=1;ip=p->next;
if(p->next!
=p)
{q=p->next;
printf(“%d”,q->data);
p->next=q->next;
free(q);
}
p=p->next;
}
printf(“%d”,p->data);
}
2.10已知单链表中的数据元素含有三类字符(即:
字母字符、数字字符和其它字符),试编写算法构造三个环形链表,使每个环形链表中只含同一类的字符,且利用原表中的结点空间作为这三个表的结点空间,头结点可另辟空间。
解:
voidsplit(nodetype*ha,nodetype*hb,nodetype*hc)
{charc;
nodetype*ra,*rb,*rc,*p=ha->next;
ra=ha;ra->next=NULL;
rb=hb;rb->next=NULL;
rc=hc;rc->next=NULL;
while(p!
=ha)
{c=p->data;
if((c>=’a’&&c<=’z’)||(c>=’A’&&c<=’Z’))
{ra->next=p;ra=p;}
elseif(c>=’0’&&c<=’9’)
{rb->next=p;rb=p;}
else
{rc->next=p;rc=p;}
p=p->next;
}
ra->next=ha;rb->next=hb;rc->next=hc;
}
2.11假设有一个循环链表的长度大于1,且表中既无头结点也无头指针。
已知p为指向链表中某结点的指针,试编写算法在链表中删除结点p的前趋结点。
解:
nodetype*delprev(nodetype*p)
{nodetype*r=p,*q=r->next;
while(q->next!
=p)
{r=r->next;q=r->next;}
r->next=p;
free(q);
return(p);
}
2.12假设有一个单向循环链表,其结点含三个域:
pre、data和next,每个结点的pre值为空指针,试编写算法将此链表改为双向环形链表。
分析:
在遍历单链表时,可以利用指针记录当前访问结点和其前驱结点。
知道了当前访问结点的前驱结点位置,就可以给当前访问结点的前驱指针赋值。
这样在遍历了整个链表后,所有结点的前驱指针均得到赋值。
Typedefstructlnode
{elemtypedata;
structlnodepre,next;
}lnode,*linklist;
voidsingletodouble(linklisth)
{linklistpre,p;
p=h->next;
pre=h;
while(p!
=h)
{p->pre=pre;
pre=p;
p=p->next;
}
p->pre=pre;
}
2.13设有一个二维数组A[m][n],假设A[0][0]存放位置在644(10),A[2][2]存放位置在676(10),每个元素占一个地址空间,求A[3][3](10)存放在什么位置?
分析根据二维数组的地址计算公式:
LOC(i,j)=LOC(0,0)+[n*i+j]*s,首先要求出数组第二维的长度,即n值。
解因为LOC(2,2)=LOC(0,0)+2*n+2=644+2*n+2=676
所以n=(676-2-644)/2=15
LOC(3,3)=LOC(0,0)+3*15+3=644+45+3=692
2.14设稀疏矩阵采用十字链表结构表示。
试写出实现两个稀疏矩阵相加的算法。
解:
依题意,C=A+B,则C中的非零元素cij只可能有3种情况:
或者是aij+bij,或者是aij(bij=0)或者是bij(aij=0)。
因此,当B加到A上时,对A矩阵的十字链表来说,或者是改变结点的val域值(a+b≠0),或者不变(b=0),或者插入一个新结点(a=0),还可能是删除一个结点(aij+bij=0)。
整个运算可从矩阵的第一行起逐行进行。
对每一行都从行表头出发分别找到A和B在该行中的第一个非零元素结点后开始比较,然后按4种不同情况分别处理(假设pa和pb分别指向A和B的十字链表中行值相同的两个结点):
若pa->col=pb->col且pa->val+pb->val≠0,则只要将aij+bij的值送到pa所指结点的值域中即可。
(2)若pa->col=pb->col且pa->val+pb->val=0,则需要在A矩阵的十字链表中删除pa所指结点,此时需改变同一行中前一结点的right域值,以及同一列中前一结点的down域值。
(3)若pa->colcol且pa->col≠0(即不是表头结点),则只需要将pa指针往右推进一步,并重新加以比较。
(4)若pa->col>pb->col或pa->col=0,则需要在A矩阵的十字链表中插入一个值为bij的结点。
实现本题功能的程序如下:
#include
#defineMAX100
structmatnode*createmat(structmatnode*h[])
/*h是建立的十字链表各行首指针的数组*/
{intm,n,t,s,i,r,c,v;
structmatnode*p,*q;
printf("行数m,列数n,非零元个数t:
");
scanf("%d,%d,%d",&m,&n,&t);
p=(structmatnode*)malloc(sizeof(structmatnode));
h[0]=p;
p->row=m;
p->col=n;
s=m>n?
m:
n;/*s为m、n中的较大者*/
for(i=1;i<=s;i++)
{
p=(structmatnode*)malloc(sizeof(structmatnode));
h[i]=p;
h[i-1]->tag.next=p;
p->row=p->col=0;
p->down=p->right=p;
}
h[s]->tag.next=h[0];
for(i=1;i<=t;i++)
{
printf("\t第%d个元素(行号r,列号c,值v):
",i);
scanf("%d,%d,%d",&r,&c,&v);
p=(structmatnode*)malloc(sizeof(structmatnode));
p->row=r;
p->col=c;
p->tag.val=v;
q=h[r];
while(q->right!
=h[r]&&q->right->colq=q->right;
p->right=q->right;
q->right=p;
q=h[c];
while(q->down!
=h[c]&&q->down->rowq=q->down;
p->down=q->down;
q->down=p;
}
return(h[0]);
}
voidprmat(structmatnode*hm)
{
structmatnode*p,*q;
printf("\n按行表输出矩阵元素:
\n");
printf("row=%dcol=%d\n",hm->row,hm->col);
p=hm->tag.next;
while(p!
=hm)
{
q=p->right;
while(p!
=q)
{
printf("\t%d,%d,%d\n",q->row,q->col,q->tag.val);
q=q->right;
}
p=p->tag.next;
}
}
structmatnode*colpred(i,j,h)
/*根据i(行号)和j(列号)找出矩阵第i行第j列的非零元素在十字链表中的前驱结点*/
inti,j;structmatnode*h[];
{
structmatnode*d;
d=h[j];
while(d->down->col!
=0&&d->down->row
d=d->down;
return(d);
}
structmatnode*addmat(ha,hb,h)
structmatnode*ha,*hb,*h[];
{
structmatnode*p,*q,*ca,*cb,*pa,*pb,*qa;
if(ha->row!
=hb->row||ha->col!
=hb->col)
{
printf("两个矩阵不是同类型的,不能相加\n");
exit(0);
}
else
{
ca=ha->tag.next;
cb=hb->tag.next;
do
{
pa=ca->right;
pb=cb->right;
qa=ca;
while(pb->col!
=0)
if(pa->colcol&&pa->col!
=0)
{
qa=pa;
pa=pa->right;
}
elseif(pa->col>pb->col||pa->col==0)
{
p=(structmatnode*)malloc(sizeof(structmatnode));
*p=*pb;
p->right=pa;
qa->right=p;
qa=p;
q=colpred(p->row,
p->col,h);
p->down=q->down;
q->down=p;
pb=pb->right;
}
else
{
pa->tag.val+=pb->tag.val;
if(pa->tag.val==0)
{
qa->right=pa->right;
q=colpred(pa->row,
pa->col,h);
q->down=pa->down;
free(pa);
}
elseqa=pa;
pa=pa->right;
pb=pb->right;
}
ca=ca->tag.next;
cb=cb->tag.next;
}while(ca->row==0);
}
return(h[0]);
}
main()
{
structmatnode*hm,*hm1,*hm2;
structmatnode*h[MAX],*h1[MAX];
printf("第一个矩阵:
\n");
hm1=createmat(h);
printf("第二个矩阵:
\n");
hm2=createmat(h1);
hm=addmat(hm1,hm2,h);
prmat(hm);
}
第二章上机内容
1.设计一个程序,生成两个按值非递减有序排列的线性表LA和LB,再将LA和LB归并为一个新的线性表LC,且LC中的数据仍按值非递减有序排列,输出线性表LA,LB,LC。
解:
#include“stdio.h”
#include“alloc.h”
typedefstructnode
{
chardata;
structnode*next;
}listnode;
typedefstructnode*link