数据结构习题参考答案64.docx

上传人:b****4 文档编号:3513590 上传时间:2022-11-23 格式:DOCX 页数:59 大小:490.18KB
下载 相关 举报
数据结构习题参考答案64.docx_第1页
第1页 / 共59页
数据结构习题参考答案64.docx_第2页
第2页 / 共59页
数据结构习题参考答案64.docx_第3页
第3页 / 共59页
数据结构习题参考答案64.docx_第4页
第4页 / 共59页
数据结构习题参考答案64.docx_第5页
第5页 / 共59页
点击查看更多>>
下载资源
资源描述

数据结构习题参考答案64.docx

《数据结构习题参考答案64.docx》由会员分享,可在线阅读,更多相关《数据结构习题参考答案64.docx(59页珍藏版)》请在冰豆网上搜索。

数据结构习题参考答案64.docx

数据结构习题参考答案64

第1章绪论

5.选择题

CCBDCA

6.试分析下面各程序段的时间复杂度。

(1)O

(1)

(2)O(m*n)

(3)O(n2)

(4)O(log3n)

(5)因为x++共执行了n-1+n-2+……+1=n(n-1)/2,所以执行时间为O(n2)

(6)O(

第2章线性表

1.选择题

BABADBCABDCDDAC

2.算法设计题(答案仅做参考)

(1)将两个递增的有序链表合并为一个递增的有序链表。

要求结果链表仍使用原来两个链表的存储空间,不另外占用其它的存储空间。

表中不允许有重复的数据。

voidMergeList_L(LinkList&La,LinkList&Lb,LinkList&Lc){

pa=La->next;pb=Lb->next;

Lc=pc=La;//用La的头结点作为Lc的头结点

while(pa&&pb){

if(pa->datadata){pc->next=pa;pc=pa;pa=pa->next;}

elseif(pa->data>pb->data){pc->next=pb;pc=pb;pb=pb->next;}

else{//相等时取La的元素,删除Lb的元素

pc->next=pa;pc=pa;pa=pa->next;

q=pb->next;deletepb;pb=q;}

}

pc->next=pa?

pa:

pb;//插入剩余段

deleteLb;//释放Lb的头结点}

(2)将两个非递减的有序链表合并为一个非递增的有序链表。

要求结果链表仍使用原来两个链表的存储空间,不另外占用其它的存储空间。

表中允许有重复的数据。

voidunion(LinkList&La,LinkList&Lb,LinkList&Lc,){

pa=La->next;pb=Lb->next;//初始化

Lc=pc=La;//用La的头结点作为Lc的头结点

Lc->next=NULL;

while(pa||pb){

if(!

pa){q=pb;pb=pb->next;}

elseif(!

pb){q=pa;pa=pa->next;}

elseif(pa->data<=pb->data){q=pa;pa=pa->next;}

else{q=pb;pb=pb->next;}

q->next=Lc->next;Lc->next=q;//插入

}

deleteLb;//释放Lb的头结点}

(3)已知两个链表A和B分别表示两个集合,其元素递增排列。

请设计算法求出A与B的交集,并存放于A链表中。

voidMix(LinkList&La,LinkList&Lb,LinkList&Lc,){

pa=la->next;pb=lb->next;∥设工作指针pa和pb;

Lc=pc=La;//用La的头结点作为Lc的头结点

while(pa&&pb)

if(pa->data==pb->data)∥交集并入结果表中。

{pc->next=pa;pc=pa;pa=pa->next;

u=pb;pb=pb->next;deleteu;}

elseif(pa->datadata){u=pa;pa=pa->next;deleteu;}

else{u=pb;pb=pb->next;deleteu;}

while(pa){u=pa;pa=pa->next;deleteu;}∥释放结点空间

while(pb){u=pb;pb=pb->next;deleteu;}∥释放结点空间

pc->next=null;∥置链表尾标记。

deleteLb;∥注:

本算法中也可对B表不作释放空间的处理

(4)已知两个链表A和B分别表示两个集合,其元素递增排列。

请设计算法求出两个集合A和B的差集(即仅由在A中出现而不在B中出现的元素所构成的集合),并以同样的形式存储,同时返回该集合的元素个数。

voidDifference(LinkedListA,B,*n)

∥A和B均是带头结点的递增有序的单链表,分别存储了一个集合,本算法求两集合的差集,存储于单链表A中,*n是结果集合中元素个数,调用时为0

{p=A->next;∥p和q分别是链表A和B的工作指针。

q=B->next;pre=A;∥pre为A中p所指结点的前驱结点的指针。

while(p!

=null&&q!

=null)

if(p->datadata){pre=p;p=p->next;*n++;}∥A链表中当前结点指针后移。

elseif(p->data>q->data)q=q->next;∥B链表中当前结点指针后移。

else{pre->next=p->next;∥处理A,B中元素值相同的结点,应删除。

u=p;p=p->next;deleteu;}∥删除结点

(6)设计一个算法,通过一趟遍历在单链表中确定值最大的结点。

ElemTypeMax(LinkListL){

if(L->next==NULL)returnNULL;

pmax=L->next;//假定第一个结点中数据具有最大值

p=L->next->next;

while(p!

=NULL){//如果下一个结点存在

if(p->data>pmax->data)pmax=p;

p=p->next;

}

returnpmax->data;

(7)设计一个算法,通过遍历一趟,将链表中所有结点的链接方向逆转,仍利用原表的存储空间。

voidinverse(LinkList&L){

//逆置带头结点的单链表L

p=L->next;L->next=NULL;

while(p){

q=p->next;//q指向*p的后继

p->next=L->next;

L->next=p;//*p插入在头结点之后

p=q;

}

}

(8)设计一个算法,删除递增有序链表中值大于mink且小于maxk的所有元素(mink和maxk是给定的两个参数,其值可以和表中的元素相同,也可以不同)。

voiddelete(LinkList&L,intmink,intmaxk){

p=L->next;//首元结点

while(p&&p->data<=mink)

{pre=p;p=p->next;}//查找第一个值>mink的结点

if(p){

while(p&&p->datanext;

//查找第一个值≥maxk的结点

q=pre->next;pre->next=p;//修改指针

while(q!

=p)

{s=q->next;deleteq;q=s;}//释放结点空间

}//if

}

(9)已知p指向双向循环链表中的一个结点,其结点结构为data、prior、next三个域,写出算法change(p),交换p所指向的结点和它的前缀结点的顺序。

知道双向循环链表中的一个结点,与前驱交换涉及到四个结点(p结点,前驱结点,前驱的前驱结点,后继结点)六条链。

voidExchange(LinkedListp)

∥p是双向循环链表中的一个结点,本算法将p所指结点与其前驱结点交换。

{q=p->llink;

q->llink->rlink=p;∥p的前驱的前驱之后继为p

p->llink=q->llink;∥p的前驱指向其前驱的前驱。

q->rlink=p->rlink;∥p的前驱的后继为p的后继。

q->llink=p;∥p与其前驱交换

p->rlink->llink=q;∥p的后继的前驱指向原p的前驱

p->rlink=q;∥p的后继指向其原来的前驱

}∥算法exchange结束。

(10)已知长度为n的线性表A采用顺序存储结构,请写一时间复杂度为O(n)、空间复杂度为O

(1)的算法,该算法删除线性表中所有值为item的数据元素。

[题目分析]在顺序存储的线性表上删除元素,通常要涉及到一系列元素的移动(删第i个元素,第i+1至第n个元素要依次前移)。

本题要求删除线性表中所有值为item的数据元素,并未要求元素间的相对位置不变。

因此可以考虑设头尾两个指针(i=1,j=n),从两端向中间移动,凡遇到值item的数据元素时,直接将右端元素左移至值为item的数据元素位置。

voidDelete(ElemTypeA[],intn)

∥A是有n个元素的一维数组,本算法删除A中所有值为item的元素。

{i=1;j=n;∥设置数组低、高端指针(下标)。

while(i

{while(i

=item)i++;∥若值不为item,左移指针。

if(i

if(i

}

[算法讨论]因元素只扫描一趟,算法时间复杂度为O(n)。

删除元素未使用其它辅助空间,最后线性表中的元素个数是j。

第3章栈和队列

1.选择题

CCDAADABCDDDBCB

2.算法设计题(答案仅做参考)

(2)回文是指正读反读均相同的字符序列,如“abba”和“abdba”均是回文,但“good”不是回文。

试写一个算法判定给定的字符向量是否为回文。

(提示:

将一半字符入栈) 

根据提示,算法可设计为:

 //以下为顺序栈的存储结构定义

 #defineStackSize100//假定预分配的栈空间最多为100个元素

 typedefcharDataType;//假定栈元素的数据类型为字符

 typedefstruct{

  DataTypedata[StackSize];

  inttop;

 }SeqStack; 

 intIsHuiwen(char*t)

  {//判断t字符向量是否为回文,若是,返回1,否则返回0

   SeqStacks;

   inti,len;

   chartemp;

   InitStack(&s);

   len=strlen(t);//求向量长度

   for(i=0;i

    Push(&s,t[i]);

   while(!

EmptyStack(&s))

    {//每弹出一个字符与相应字符比较

     temp=Pop(&s);

     if(temp!

=S[i]) return0;//不等则返回0

     elsei++;

    } 

   return1;//比较完毕均相等则返回1

  }

(3)设从键盘输入一整数的序列:

a1,a2,a3,…,an,试编写算法实现:

用栈结构存储输入的整数,当ai≠-1时,将ai进栈;当ai=-1时,输出栈顶整数并出栈。

算法应对异常情况(入栈满等)给出相应的信息。

#definemaxsize栈空间容量

voidInOutS(ints[maxsize])

//s是元素为整数的栈,本算法进行入栈和退栈操作。

{inttop=0;//top为栈顶指针,定义top=0时为栈空。

for(i=1;i<=n;i++)//n个整数序列作处理。

{scanf(“%d”,&x);//从键盘读入整数序列。

if(x!

=-1)//读入的整数不等于-1时入栈。

if(top==maxsize-1){printf(“栈满\n”);exit(0);}elses[++top]=x;//x入栈。

else//读入的整数等于-1时退栈。

{if(top==0){printf(“栈空\n”);exit(0);}elseprintf(“出栈元素是%d\n”,s[top--]);}}

}//算法结束。

(4)从键盘上输入一个后缀表达式,试编写算法计算表达式的值。

规定:

逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、*、/四种运算。

例如:

23434+2*$。

[题目分析]逆波兰表达式(即后缀表达式)求值规则如下:

设立运算数栈OPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPND栈。

当扫描到运算符时,从OPND退出两个数,进行相应运算,结果再压入OPND栈。

这个过程一直进行到读出表达式结束符$,这时OPND栈中只有一个数,就是结果。

floatexpr()

//从键盘输入逆波兰表达式,以‘$’表示输入结束,本算法求逆波兰式表达式的值。

{floatOPND[30];//OPND是操作数栈。

 init(OPND);//两栈初始化。

floatnum=0.0;//数字初始化。

scanf(“%c”,&x);//x是字符型变量。

while(x!

=’$’)

{switch

{case‘0’<=x<=’9’:

while((x>=’0’&&x<=’9’)||x==’.’)//拼数

if(x!

=’.’)//处理整数

{num=num*10+(ord(x)-ord(‘0’));scanf(“%c”,&x);}

else//处理小数部分。

{scale=10.0;scanf(“%c”,&x);

while(x>=’0’&&x<=’9’)

{num=num+(ord(x)-ord(‘0’)/scale;

scale=scale*10;scanf(“%c”,&x);}

}//else

push(OPND,num);num=0.0;//数压入栈,下个数初始化

casex=‘’:

break;//遇空格,继续读下一个字符。

casex=‘+’:

push(OPND,pop(OPND)+pop(OPND));break;

casex=‘-’:

x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break;

casex=‘*’:

push(OPND,pop(OPND)*pop(OPND));break;

casex=‘/’:

x1=pop(OPND);x2=pop(OPND);push(OPND,x2/x1);break;

default:

//其它符号不作处理。

}//结束switch

scanf(“%c”,&x);//读入表达式中下一个字符。

}//结束while(x!

=‘$’)

printf(“后缀表达式的值为%f”,pop(OPND));

}//算法结束。

[算法讨论]假设输入的后缀表达式是正确的,未作错误检查。

算法中拼数部分是核心。

若遇到大于等于‘0’且小于等于‘9’的字符,认为是数。

这种字符的序号减去字符‘0’的序号得出数。

对于整数,每读入一个数字字符,前面得到的部分数要乘上10再加新读入的数得到新的部分数。

当读到小数点,认为数的整数部分已完,要接着处理小数部分。

小数部分的数要除以10(或10的幂数)变成十分位,百分位,千分位数等等,与前面部分数相加。

在拼数过程中,若遇非数字字符,表示数已拼完,将数压入栈中,并且将变量num恢复为0,准备下一个数。

这时对新读入的字符进入‘+’、‘-’、‘*’、‘/’及空格的判断,因此在结束处理数字字符的case后,不能加入break语句。

(5)假设以I和O分别表示入栈和出栈操作。

栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。

下面所示的序列中哪些是合法的?

A.IOIIOIOOB.IOOIOIIOC.IIIOIOIOD.IIIOOIOO

通过对

的分析,写出一个算法,判定所给的操作序列是否合法。

若合法,返回true,否则返回false(假定被判定的操作序列已存入一维数组中)。

A和D是合法序列,B和C是非法序列。

设被判定的操作序列已存入一维数组A中。

intJudge(charA[])

//判断字符数组A中的输入输出序列是否是合法序列。

如是,返回true,否则返回false。

{i=0;//i为下标。

j=k=0;//j和k分别为I和字母O的的个数。

while(A[i]!

=‘\0’)//当未到字符数组尾就作。

{switch(A[i])

{case‘I’:

j++;break;//入栈次数增1。

case‘O’:

k++;if(k>j){printf(“序列非法\n”);exit(0);}

}

i++;//不论A[i]是‘I’或‘O’,指针i均后移。

}

if(j!

=k){printf(“序列非法\n”);return(false);}

else{printf(“序列合法\n”);return(true);}

}//算法结束。

[算法讨论]在入栈出栈序列(即由‘I’和‘O’组成的字符串)的任一位置,入栈次数(‘I’的个数)都必须大于等于出栈次数(即‘O’的个数),否则视作非法序列,立即给出信息,退出算法。

整个序列(即读到字符数组中字符串的结束标记‘\0’),入栈次数必须等于出栈次数(题目中要求栈的初态和终态都为空),否则视为非法序列。

(6)假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素站点(注意不设头指针),试编写相应的置空队、判队空、入队和出队等算法。

 

算法如下:

 //先定义链队结构:

 typedefstructqueuenode{

   Datatypedata;

   structqueuenode*next;

  }QueueNode;//以上是结点类型的定义

 typedefstruct{

   queuenode*rear;

  }LinkQueue;//只设一个指向队尾元素的指针

 

(1)置空队

  voidInitQueue(LinkQueue*Q)

   {//置空队:

就是使头结点成为队尾元素

    QueueNode*s;

    Q->rear=Q->rear->next;//将队尾指针指向头结点

    while(Q->rear!

=Q->rear->next)//当队列非空,将队中元素逐个出队

     {s=Q->rear->next;

      Q->rear->next=s->next;

      free(s);

     }//回收结点空间

   }

 

(2)判队空 

  intEmptyQueue(LinkQueue*Q)

   {//判队空

    //当头结点的next指针指向自己时为空队

    returnQ->rear->next->next==Q->rear->next;

   }

 (3)入队

  voidEnQueue(LinkQueue*Q,Datatypex)

   {//入队

    //也就是在尾结点处插入元素

    QueueNode*p=(QueueNode*)malloc(sizeof(QueueNode));//申请新结点

    p->data=x;p->next=Q->rear->next;//初始化新结点并链入

    Q-rear->next=p; 

    Q->rear=p;//将尾指针移至新结点

   }

 (4)出队

  DatatypeDeQueue(LinkQueue*Q)

   {//出队,把头结点之后的元素摘下

    Datatypet;

    QueueNode*p;

    if(EmptyQueue(Q))

      Error("Queueunderflow");

    p=Q->rear->next->next;//p指向将要摘下的结点

    x=p->data;//保存结点中数据

    if(p==Q->rear)

     {//当队列中只有一个结点时,p结点出队后,要将队尾指针指向头结点

      Q->rear=Q->rear->next;Q->rear->next=p->next;}

    else 

      Q->rear->next->next=p->next;//摘下结点p

    free(p);//释放被删结点

    returnx;

   }

(7)假设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag==0和tag==1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。

试编写与此结构相应的插入(enqueue)和删除(dlqueue)算法。

【解答】

循环队列类定义

#include

templateclassQueue{//循环队列的类定义

public:

Queue(int=10);

~Queue(){delete[]Q;}

voidEnQueue(Type&item);

TypeDeQueue();

TypeGetFront();

voidMakeEmpty(){front=rear=tag=0;}//置空队列

intIsEmpty()const{returnfront==rear&&tag==0;}//判队列空否

intIsFull()const{returnfront==rear&&tag==1;}//判队列满否

private:

intrear,front,tag;//队尾指针、队头指针和队满标志

Type*Q;//存放队列元素的数组

intm;//队列最大可容纳元素个数

}

构造函数

template

Queue:

:

Queue(intsz):

rear(0),front(0),tag(0),m(sz){

//建立一个最大具有m个元素的空队列。

Q=newType[m];//创建队列空间

assert(Q!

=0);//断言:

动态存储分配成功与否

}

插入函数

template

voidQueue:

:

EnQueue(Type&item){

assert(!

IsFull());

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1