- 1.49 MB
- 2022-04-22 11:36:41 发布
- 1、本文档共5页,可阅读全部内容。
- 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
- 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
- 文档侵权举报电话:19940600175。
'第2章线性表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;}∥删除结点(5)设计算法将一个带头结点的单链表A分解为两个具有相同结构的链表B、C,其中B表的结点为A表中值小于零的结点,而C表的结点为A表中值大于零的结点(链表A的元素类型为整型,要求B、C表利用A表的结点)。(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){//逆置带头结点的单链表Lp=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的前驱的前驱之后继为pp->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=’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);}}//elsepush(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://其它符号不作处理。}//结束switchscanf(“%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]!=‘ ’)//当未到字符数组尾就作。{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’的个数),否则视作非法序列,立即给出信息,退出算法。整个序列(即读到字符数组中字符串的结束标记‘ ’),入栈次数必须等于出栈次数(题目中要求栈的初态和终态都为空),否则视为非法序列。(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)算法。【解答】循环队列类定义#includetemplateclassQueue{//循环队列的类定义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;//队列最大可容纳元素个数}构造函数templateQueue::Queue(intsz):rear(0),front(0),tag(0),m(sz){//建立一个最大具有m个元素的空队列。Q=newType[m];//创建队列空间assert(Q!=0);//断言:动态存储分配成功与否}插入函数templatevoidQueue::EnQueue(Type&item){
assert(!IsFull());//判队列是否不满,满则出错处理rear=(rear+1)%m;//队尾位置进1,队尾指针指示实际队尾位置Q[rear]=item;//进队列tag=1;//标志改1,表示队列不空}删除函数templateTypeQueue::DeQueue(){assert(!IsEmpty());//判断队列是否不空,空则出错处理front=(front+1)%m;//队头位置进1,队头指针指示实际队头的前一位置tag=0;//标志改0,表示栈不满returnQ[front];//返回原队头元素的值}读取队头元素函数templateTypeQueue::GetFront(){assert(!IsEmpty());//判断队列是否不空,空则出错处理returnQ[(front+1)%m];//返回队头元素的值}(8)如果允许在循环队列的两端都可以进行插入和删除操作。要求:①写出循环队列的类型定义;②写出“从队尾删除”和“从队头插入”的算法。[题目分析]用一维数组v[0..M-1]实现循环队列,其中M是队列长度。设队头指针front和队尾指针rear,约定front指向队头元素的前一位置,rear指向队尾元素。定义front=rear时为队空,(rear+1)%m=front为队满。约定队头端入队向下标小的方向发展,队尾端入队向下标大的方向发展。(1)#defineM队列可能达到的最大长度typedefstruct{elemtpdata[M];intfront,rear;}cycqueue;(2)elemtpdelqueue(cycqueueQ)//Q是如上定义的循环队列,本算法实现从队尾删除,若删除成功,返回被删除元素,否则给出出错信息。{if(Q.front==Q.rear){printf(“队列空”);exit(0);}Q.rear=(Q.rear-1+M)%M;//修改队尾指针。return(Q.data[(Q.rear+1+M)%M]);//返回出队元素。}//从队尾删除算法结束voidenqueue(cycqueueQ,elemtpx)//Q是顺序存储的循环队列,本算法实现“从队头插入”元素x。{if(Q.rear==(Q.front-1+M)%M){printf(“队满”;exit(0);)Q.data[Q.front]=x;//x入队列
Q.front=(Q.front-1+M)%M;//修改队头指针。}//结束从队头插入算法。(9)已知Ackermann函数定义如下:①写出计算Ack(m,n)的递归算法,并根据此算法给出出Ack(2,1)的计算过程。②写出计算Ack(m,n)的非递归算法。intAck(intm,n){if(m==0)return(n+1);elseif(m!=0&&n==0)return(Ack(m-1,1));elsereturn(Ack(m-1,Ack(m,m-1));}//算法结束(1)Ack(2,1)的计算过程Ack(2,1)=Ack(1,Ack(2,0))//因m<>0,n<>0而得=Ack(1,Ack(1,1))//因m<>0,n=0而得=Ack(1,Ack(0,Ack(1,0)))//因m<>0,n<>0而得=Ack(1,Ack(0,Ack(0,1)))//因m<>0,n=0而得=Ack(1,Ack(0,2))//因m=0而得=Ack(1,3)//因m=0而得=Ack(0,Ack(1,2))//因m<>0,n<>0而得=Ack(0,Ack(0,Ack(1,1)))//因m<>0,n<>0而得=Ack(0,Ack(0,Ack(0,Ack(1,0))))//因m<>0,n<>0而得=Ack(0,Ack(0,Ack(0,Ack(0,1))))//因m<>0,n=0而得=Ack(0,Ack(0,Ack(0,2)))//因m=0而得=Ack(0,Ack(0,3))//因m=0而得=Ack(0,4)//因n=0而得=5//因n=0而得(2)intAckerman(intm,intn){intakm[M][N];inti,j;for(j=0;j//定义在头文件"RecurveList.h"中classList;classListNode{//链表结点类friendclassList;private:intdata;//结点数据ListNode*link;//结点指针ListNode(constintitem):data(item),link(NULL){}//构造函数};classList{//链表类private:ListNode*first,current;intMax(ListNode*f);intNum(ListNode*f);floatAvg(ListNode*f,int&n);public:List():first(NULL),current(NULL){}//构造函数~List(){}//析构函数ListNode*NewNode(constintitem);//创建链表结点,其值为itemvoidNewList(constintretvalue);//建立链表,以输入retvalue结束voidPrintList();//输出链表所有结点数据intGetMax(){returnMax(first);}//求链表所有数据的最大值intGetNum(){returnNum(first);}//求链表中数据个数floatGetAvg(){returnAvg(first);}//求链表所有数据的平均值};ListNode*List::NewNode(constintitem){//创建新链表结点ListNode*newnode=newListNode(item);returnnewnode;}voidList::NewList(constintretvalue){//建立链表,以输入retvalue结束first=NULL;intvalue;ListNode*q;cout<<"Inputyourdata:n";//提示cin>>value;//输入while(value!=retvalue){//输入有效q=NewNode(value);//建立包含value的新结点if(first==NULL)first=current=q;//空表时,新结点成为链表第一个结点else{current->link=q;current=q;}//非空表时,新结点链入链尾cin>>value;//再输入}current->link=NULL;//链尾封闭}
voidList::PrintList(){//输出链表cout<<"nTheListis:n";ListNode*p=first;while(p!=NULL){cout<data<<"";p=p->link;}cout<<‘n’;}intList::Max(ListNode*f){//递归算法:求链表中的最大值if(f->link==NULL)returnf->data;//递归结束条件inttemp=Max(f->link);//在当前结点的后继链表中求最大值if(f->data>temp)returnf->data;//如果当前结点的值还要大,返回当前检点值elsereturntemp;//否则返回后继链表中的最大值}intList::Num(ListNode*f){//递归算法:求链表中结点个数if(f==NULL)return0;//空表,返回0return1+Num(f->link);//否则,返回后继链表结点个数加1}floatList::Avg(ListNode*f,int&n){//递归算法:求链表中所有元素的平均值if(f->link==NULL)//链表中只有一个结点,递归结束条件{n=1;return(float)(f->data);}else{floatSum=Avg(f->link,n)*n;n++;return(f->data+Sum)/n;}}#include"RecurveList.h"//定义在主文件中intmain(intargc,char*argv[]){Listtest;intfinished;cout<<“输入建表结束标志数据:”;cin>>finished;//输入建表结束标志数据test.NewList(finished);//建立链表test.PrintList();//打印链表cout<<"nTheMaxis:"<