1、对一般二叉树,仅根据一个先序、中序、后序遍历,
不能确定另一个遍历序列。但对于满二叉树,任一结点的左右子树均含有数量相等的结点,根据此性质,可将任一遍历序列转为另一遍历序列(即任一遍历序列均可确定一棵二叉树)。
voidPreToPost(ElemTypepre[],post[],intl1,h1,l2,h2)
//将满二叉树的先序序列转为后序序列,l1,h1,l2,h2是序列初始和最后结点的下标。
{if(h1>=l1){post[h2]=pre[l1];//根结点half=(h1-l1)/2;//左或右子树的结点数
PreToPost(pre,post,l1+1,l1+half,l2,l2+half-1)//将左子树先序序列转为后序序列PreToPost(pre,post,l1+half+1,h1,l2+half,h2-1)//将右子树先序序列转为后序序列}}//PreToPost
32..叶子结点只有在遍历中才能知道,这里使用中序递归遍历。设置前驱结点指针pre,初始为空。第一个叶子结点由指针head指向,遍历到叶子结点时,就将它前驱的rchild指针指向它,最后叶子结点的rchild为空。LinkedListhead,pre=null;//全局变量LinkedListInOrder(BiTreebt)
//中序遍历二叉树bt,将叶子结点从左到右链成一个单链表,表头指针为head{if(bt){InOrder(bt->lchild);//中序遍历左子树
if(bt->lchild==null&&bt->rchild==null)//叶子结点if(pre==null){head=bt;pre=bt;}//处理第一个叶子结点else{pre->rchild=bt;pre=bt;}//将叶子结点链入链表InOrder(bt->rchild);//中序遍历左子树pre->rchild=null;//设置链表尾}
return(head);}//InOrder
时间复杂度为O(n),辅助变量使用head和pre,栈空间复杂度O(n)
2、在有向图G中,如果r到G中的每个结点都有路径可达,则称结点r为G的根结点。编写一个算法完成下列功能:(1).建立有向图G的邻接表存储结构;(2).判断有向图G是否有根,若有,则打印出所有根结点的值。3、设T是一棵满二叉树,编写一个将T的先序遍历序列转换为后序遍历序列的递归算法。4、本题应使用深度优先遍历,从主调函数进入dfs(v)时,开始记数,若退出dfs()前,已访问完有向图的全部顶点(设为n个),则有向图有根,v为根结点。将n个顶点从1到n编号,各调用一次dfs()过程,就可以求出全部的根结点。题中有
向图的邻接表存储结构、记顶点个数的变量、以及访问标记数组等均设计为全局变量。建立有向图g的邻接表存储结构参见上面第2题,这里只给出判断有向图是否有根的算法。
intnum=0,visited[]=0//num记访问顶点个数,访问数组visited初始化。constn=用户定义的顶点数;AdjListg;//用邻接表作存储结构的有向图g。voiddfs(v)
{visited[v]=1;num++;//访问的顶点数+1if(nu
m==n){printf(“%d是有向图的根。\\n”,v);num=0;}//if
p=g[v].firstarc;while(p)
{if(visied[p->adjvex]==0)dfs(p->adjvex);p=p->next;}//while
visited[v]=0;num--;//恢复顶点v}//dfs
voidJudgeRoot()
//判断有向图是否有根,有根则输出之。{staticinti;
for(i=1;i<=n;i++)//从每个顶点出发,调用dfs()各一次。{num=0;visited[1..n]=0;dfs(i);}}//JudgeRoot
算法中打印根时,输出顶点在邻接表中的序号(下标),若要输出顶点信息,可使用g[i].vertex。
5、题目中要求矩阵两行元素的平均值按递增顺序排序,由于每行元素个数相等,按平均值排列与按每行元素之和排列是一个意思。所以应先求出各行元素之和,放入一维数组中,然后选择一种排序方法,对该数组进行排序,注意在排序时若有元素移动,则与之相应的行中各元素也必须做相应变动。voidTranslation(float*matrix,intn)
//本算法对n×n的矩阵matrix,通过行变换,使其各行元素的平均值按递增排列。
{inti,j,k,l;
floatsum,min;//sum暂存各行元素之和float*p,*pi,*pk;for(i=0;i<n;i++)
{sum=0.0;pk=matrix+i*n;//pk指向矩阵各行第1个元素.for(j=0;j<n;j++){sum+=*(pk);pk++;}//求一行元素之和.*(p+i)=sum;//将一行元素之和存入一维数组.
}//fori
for(i=0;i<n-1;i++)//用选择法对数组p进行排序{min=*(p+i);k=i;//初始设第i行元素之和最小.
for(j=i+1;j<n;j++)if(p[j]<min){k=j;min=p[j];}//记新的最小值及行号.if(i!=k)//若最小行不是当前行,要进行交换(行元素及行元素之和){pk=matrix+n*k;//pk指向第k行第1个元素.pi=matrix+n*i;//pi指向第i行第1个元素.for(j=0;j<n;j++)//交换两行中对应元素.{sum=*(pk+j);*(pk+j)=*(pi+j);*(pi+j)=sum;}
sum=p[i];p[i]=p[k];p[k]=sum;//交换一维数组中元素之和.}//if}//fori
free(p);//释放p数组.}//Translation
[算法分析]算法中使用选择法排序,比较次数较多,但数据交换(移动)较少.若用其它排序方法,虽可减少比较次数,但数据移动会增多.算法时间复杂度为O(n2).6、冒泡排序算法是把大的元素向上移(气泡的上浮),也可以把小的元素向下移(气泡的下沉)请给出上浮和下沉过程交替的冒泡排序算法。
48.有n个记录存储在带头结点的双向链表中,现用双向起泡排序法对其按上升序进行排序,请写出这种排序的算法。(注:双向起泡排序即相邻两趟排序向相反方向起泡)
7、设一棵二叉树的结点结构为(LLINK,INFO,RLINK),ROOT为指向该二叉树根结点的指针,p和q分别为指向该二叉树中任意两个结点的指针,试编写一算法ANCESTOR(ROOT,p,q,r),该算法找到p和q的最近共同祖先结点r。8
、本题应使用深度优先遍历,从主调函数进入dfs(v)时,
开始记数,若退出dfs()前,已访问完有向图的全部顶点(设为n个),则有向图有根,v为根结点。将n个顶点从1到n编号,各调用一次dfs()过程,就可以求出全部的根结点。题中有向图的邻接表存储结构、记顶点个数的变量、以及访问标记数组等均设计为全局变量。建立有向图g的邻接表存储结构参见上面第2题,这里只给出判断有向图是否有根的算法。
intnum=0,visited[]=0//num记访问顶点个数,访问数组visited初始化。constn=用户定义的顶点数;AdjListg;//用邻接表作存储结构的有向图g。voiddfs(v)
{visited[v]=1;num++;//访问的顶点数+1
if(num==n){printf(“%d是有向图的根。\\n”,v);num=0;}//ifp=g[v].firstarc;while(p)
{if(visied[p->adjvex]==0)dfs(p->adjvex);p=p->next;}//while
visited[v]=0;num--;//恢复顶点v}//dfs
voidJudgeRoot()
//判断有向图是否有根,有根则输出之。{staticinti;
for(i=1;i<=n;i++)//从每个顶点出发,调用dfs()各一次。{num=0;visited[1..n]=0;dfs(i);}}//JudgeRoot
算法中打印根时,输出顶点在邻接表中的序号(下标),若要输出顶点信息,可使用g[i].vertex。
9、给定n个村庄之间的交通图,若村庄i和j之间有道路,则将顶点i和j用边连接,边上的Wij表示这条道路的长度,现在要从这n个村庄中选择一个村庄建一所医院,问这所医院应建在哪个村庄,才能使离医院最远的村庄到医院的路程最短?试设计一个解答上述问题的算法,并应用该算法解答如图所示的实例。20分
voidHospital(AdjMatrixw,intn)
//在以邻接带权矩阵表示的n个村庄中,求医院建在何处,使离医院最远的村庄到医院的路径最短。
{for(k=1;k<=n;k++)//求任意两顶点间的最短路径for(i=1;i<=n;i++)for(j=1;j<=n;j++)
if(w[i][k]+w[k][j]<w[i][j])w[i][j]=w[i][k]+w[k][j];m=MAXINT;//设定m为机器内最大整数。for(i=1;i<=n;i++)//求最长路径中最短的一条。{s=0;
for(j=1;j<=n;j++)//求从某村庄i(1<=i<=n)到其它村庄的最长路径。if(w[i][j]>s)s=w[i][j];
if(s<=m){m=s;k=i;}//在最长路径中,取最短的一条。m记最长路径,k记出发顶点的下标。
Printf(“医院应建在%d村庄,到医院距离为%d\\n”,i,m);}//for
}//算法结束
对以上实例模拟的过程略。各行中最大数依次是9,9,6,7,9,9。这几个最大数中最小者为6,故医院应建在第三个村庄中,离医院最远的村庄到医院的距离是6。
1、对图1所示的连通网G,请用Prim算法构造其最小生成树(每选取一条边画一个图)
。
10、由二叉树的前序遍历和中序遍历序列能确定唯一的一棵二叉树,下面程序的作用是实现由已知某二叉树的前序遍历和中序遍历序列,生成一棵用二叉链表表示的二叉树并打印出后序遍历序列,请写出程序所缺的语句。#defineMAX100typedefstructNode
{charinfo;structNode*llink,*rlink;}TNODE;charpred[MAX],inod[MAX];main(intargc,int**argv){TNODE*root;if(argc<3)exit0;
strcpy(pred,argv[1]);strcpy(inod,argv[2]);root=restore(pred,inod,strlen(pred));postorder(root);}
TNODE*restore(char*ppos,char*ipos,intn){TNODE*ptr;char*rpos;intk;if(n<=0)returnNULL;ptr->info=(1)_______;
for((2)_______;rpos<ipos+n;rpos++)if(*rpos==*ppos)break;k=(3)_______;
ptr->llink=restore(ppos+1,(4)_______,k);
ptr->rlink=restore((5)_______+k,rpos+1,n-1-k);returnptr;}
postorder(TNODE*ptr){if(ptr=NULL)return;
postorder(ptr->llink);postorder(ptr->rlink);printf(“%c”,ptr->info);}
11、有一种简单的排序算法,叫做计数排序(countsorting)。这种排序算法对一个待排序的表(用数组表示)进行排序,并将排序结果存放到另一个新的表中。必须注意的是,表中所有待排序的关键码互不相同,计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少个记录的关键码比该记录的关键码小,假设针对某一个记录,统计出的计数值为c,那么,这个记录在新的有序表中的合适的存放位置即为c。
(1)(3分)给出适用于计数排序的数据表定义;
(2)(7分)使用Pascal或C语言编写实现计数排序的算法;(3)(4分)对于有n个记录的表,关键码比较次数是多少?
(4)(3分)与简单选择排序相比较,这种方法是否更好?为什么?
12、二部图(bipartitegraph)G=(V,E)是一个能将其结点集V分为两不相交子集V1和V2=V-V1的无向图,使得:V1中的任何两个结点在图G中均不相邻,V2中的任何结点在图G中也均不相邻。(1).请各举一个结点个数为5的二部图和非二部图的例子。(2).请用C或PASCAL编写一个函数BIPARTITE判断一个连通无向图G是否是二部图,并分析程序的时间复杂度。设G用二维数组A来表示,大小为n*n(n为结点个数)。请在程序中加必要的注释。若有必要可直接利用堆栈或队列操作。【
13、设一棵二叉树的结点结构为(LLINK,INFO,RLINK),ROOT为指向该二叉树根结点的指针,p和q分别为指向该二叉树中任意两个结点的指针,试编写一算法ANCESTOR(ROOT,p,q,r),该算法找到p和q的最近共同祖先结点r。
14、若第n件物品能放入背包,则问题变为能否再从n-1件物品中选出若干件放入背包(这时背包可放入物品的重量变为s-w[n])。若第n件物品不能放入背包,则考虑从n-1件
物品选若干件放入背包(这时背包可放入物品仍为s)。
若最终s=0,则有一解;否则,若s<0或虽然s>0但物品数n<1,则无解。(1)s-w[n],n-1//Knap(s-w[n],n-1)=true(2)s,n-1//Knap←Knap(s,n-1)15、(1)p->rchild(2)p->lchild(3)p->lchild(4)ADDQ(Q,p->lchild)(5)ADDQ(Q,p->rchild)
25.(1)t->rchild!=null(2)t->rchild!=null(3)N0++(4)count(t->lchild)(5)count(t->rchild)26..(1)top++(2)stack[top]=p->rchild(3)top++(4)stack[top]=p->lchild27.(1)*ppos//根结点(2)rpos=ipos(3)rpos–ipos(4)ipos(5)ppos+1
16、设t是给定的一棵二叉树,下面的递归程序count(t)用于求得:二叉树t中具有非空的左,右两个儿子的结点个数N2;只有非空左儿子的个数NL;只有非空右儿子的结点个数NR和叶子结点个数N0。N2、NL、NR、N0都是全局量,且在调用count(t)之前都置为0.typedefstructnode
{intdata;structnode*lchild,*rchild;}node;intN2,NL,NR,N0;voidcount(node*t)
{if(t->lchild!=NULL)if(1)___N2++;elseNL++;elseif(2)___NR++;else(3)__;
if(t->lchild!=NULL)(4)____;if(t->rchild!=NULL)(5)____;}
26.树的先序非递归算法。voidexample(b)btree*b;
{btree*stack[20],*p;inttop;if(b!=null)
{top=1;stack[top]=b;while(top>0){p=stack[top];top--;
printf(“%d”,p->data);if(p->rchild!=null){(1)___;(2)___;}
if(p->lchild!=null)(3)___;(4)__;}}}}
17、#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--]);}}
}//算法结
18、有一个带头结点的单链表,每个结点包括两个域,一个是整型域info,另一个是指向下一个结点的指针域next。假设单链表已建立,设计算法删除单链表中所有重复出现的结点,使得info域相等的结点只保留一个。#include<stdio.h>typedefchardatatype;typedefstructnode{datatypedata;structnode*next;}listnode;
typedeflistnode*linklist;
/*--------------------------------------------*/
/*删除单链表中重复的结点*//*--------------------------------------------*/linklistdeletelist(linklisthead){listnode*p,*s,*q;p=head->next;while(p){s=p;
q=p->next;while(q)
if(q->data==p->data){s->next=q->next;free(q);q=s->next;}else{s=q;/*找与P结点值相同的结点*/q=q->next;}
p=p->next;}
returnhead;}
19、在有向图G中,如果r到G中的每个结点都有路径可达,则称结点r为G的根结点。编写一个算法完成下列功能:(1).建立有向图G的邻接表存储结构;(2).判断有向图G是否有根,若有,则打印出所有根结点的值。20、两棵空二叉树或仅有根结点的二叉树相似;对非空二叉树,可判左右子树是否相似,采用递归算法。
intSimilar(BiTreep,q)//判断二叉树p和q是否相似{if(p==null&&q==null)return(1);
elseif(!p&&q||p&&!q)return(0);elsereturn(Similar(p->lchild,q->lchild)&&Similar(p->rchild,q->rchild))}//结束Similar
21、数组A和B的元素分别有序,欲将两数组合并到C数组,使C仍有序,应将A和B拷贝到C,只要注意A和B数组指针的使用,以及正确处理一数组读完数据后将另一数组余下元素复制到C中即可。voidunion(intA[],B[],C[],m,n)
//整型数组A和B各有m和n个元素,前者递增有序,后者递减有序,本算法
将A和B归并为递增有序的数组C。
{i=0;j=n-1;k=0;//i,j,k分别是数组A,B和C的下标,因用C描述,下标从0开始
while(i<m&&j>=0)
if(a[i]<b[j])c[k++]=a[i++]elsec[k++]=b[j--];while(i<m)c[k++]=a[i++];while(j>=0)c[k++]=b[j--];}算法结束
4、要求二叉树按二叉链表形式存储。15分(1)写一个建立二叉树的算法。(2)写一个判别给定的二叉树是否是完全二叉树的算法。BiTreeCreat()//建立二叉树的二叉链表形式的存储结构{ElemTypex;BiTreebt;
scanf(“%d”,&x);//本题假定结点数据域为整型if(x==0)bt=null;elseif(x>0)
{bt=(BiNode*)malloc(sizeof(BiNode));
bt->data=x;bt->lchild=creat();bt->rchild=creat();}
elseerror(“输入错误”);return(bt);}//结束BiTree
intJudgeComplete(BiTreebt)//判断二叉树是否是完全二叉树,如是,返回1,否则,返回0
{inttag=0;BiTreep=bt,Q[];//Q是队列,元素是二叉树结点指针,容量足够大if(p==null)return(1);
QueueInit(Q);QueueIn(Q,p);//初始化队列,根结点指针入队while(!QueueEmpty(Q)){p=QueueOut(Q);//出队
if(p->lchild&&!tag)QueueIn(Q,p->lchild);//左子女入队else{if(p->lchild)return0;//前边已有结点为空,本结点不空elsetag=1;//首次出现结点为空
if(p->rchild&&!tag)QueueIn(Q,p->rchild);//右子女入队elseif(p->rchild)return0;elsetag=1;}//while
return1;}//JudgeComplete
22、设T是一棵满二叉树,编写一个将T的先序遍历序列转换为后序遍历序列的递归算法。2
3、根据二叉排序树中序遍历所得结点值为增序的性质,
在遍历中将当前遍历结点与其前驱结点值比较,即可得出结论,为此设全局指针变量pre(初值为null)和全局变量flag,初值为true。若非二叉排序树,则置flag为false。#definetrue1#definefalse0
typedefstructnode
{datatypedata;structnode*llink,*rlink;}*BTree;voidJudgeBST(BTreet,intflag)
//判断二叉树是否是二叉排序树,本算法结束后,在调用程序中由flag得出结论。
{if(t!=null&&flag){Judgebst(t->llink,flag);//中序遍历左子树
if(pre==null)pre=t;//中序遍历的第一个结点不必判断
elseif(pre->data<t->data)pre=t;//前驱指针指向当前结点else{flag=flase;}//不是完全二叉树Judgebst(t->rlink,flag);//中序遍历右子树}//JudgeBST算法结束
24、对二叉树的某层上的结点进行运算,采用队列结构按层次遍历最适宜。intLeafKlevel(BiTreebt,intk)//求二叉树bt的第k(k>1)层上叶子结点个数{if(bt==null||k<1)return(0);BiTreep=bt,Q[];//Q是队列,元素是二叉树结点指针,容量足够大intfront=0,rear=1,leaf=0;//front和rear是队头和队尾指针,leaf是叶子结点数intlast=1,level=1;Q[1]=p;//last是二叉树同层最右结点的指针,level是二叉树的层数
while(front<=rear){p=Q[++front];
if(level==k&&!p->lchild&&!p->rchild)leaf++;//叶子结点
if(p->lchild)Q[++rear]=p->lchild;//左子女入队if(p->rchild)Q[++rear]=p->rchild;//右子女入队if(front==last){level++;//二叉树同层最右结点已处理,层数增1last=rear;}//last移到指向下层最右一元素if(level>k)return(leaf);//层数大于k后退出运行}//while}//结束LeafKLevel
25、请编写一个判别给定二叉树是否为二叉排序树的算法,设二叉树用llink-rlink法存储。
26、请设计一个算法,要求该算法把二叉树的叶子结点按从左到右的顺序连成一个单链表,表头指针为head。二叉树按二叉链表方式存储,链接时用叶子结点的右指针域来存放单链表指针。分析你的算法的时、空复杂度。
27、二部图(bipartitegraph)G=(V,E)是一个能将其结点集V分为两不相交子集V1和V2=V-V1的无向图,使得:V1中的任何两个结点在图G中均不相
邻,V2中的任何结点在图G中也均不相邻。(1).请各举一个结点个数为5的二部图和非二部图的例子。(2).请用C或PASCAL编写一个函数BIPARTITE判断一个连通无向图G是否是二部图,并分析程序的时间复杂度。设G用二维数组A来表示,大小为n*n(n为结点个数)。请在程序中加必要的注释。若有必要可直接利用堆栈或队列
操作。【
28、后序遍历最后访问根结点,即在递归算法中,根是压在栈底的。采用后序非递归算法,栈中存放二叉树结点的指针,当访问到某结点时,栈中所有元素均为该结点的祖先。本题要找p和q的最近共同祖先结点r,不失一般性,设p在q的左边。后序遍历必然先遍历到结点p,栈中元素均为p的祖先。将栈拷入另一辅助栈中。再继续遍历到结点q时,将栈中元素从栈顶开始逐个到辅助栈中去匹配,第一个匹配(即相等)的元素就是结点p和q的最近公共祖先。typedefstruct
{BiTreet;inttag;//tag=0表示结点的左子女已被访问,tag=1表示结点的右子女已被访问}stack;
stacks[],s1[];//栈,容量够大
BiTreeAncestor(BiTreeROOT,p,q,r)//求二叉树上结点p和q的最近的共同祖先结点r。
{top=0;bt=ROOT;
while(bt!=null||top>0)
{while(bt!=null&&bt!=p&&bt!=q)//结点入栈{s[++top].t=bt;s[top].tag=0;bt=bt->lchild;}//沿左分枝向下
if(bt==p)//不失一般性,假定p在q的左侧,遇结点p时,栈中元素均为p的祖先结点
{for(i=1;i<=top;i++)s1[i]=s[i];top1=top;}//将栈s的元素转入辅助栈s1保存if(bt==q)//找到q结点。
for(i=top;i>0;i--)//;将栈中元素的树结点到s1去匹配{pp=s[i].t;
for(j=top1;j>0;j--)
if(s1[j].t==pp){printf(“p和q的最近共同的祖先已找到”);return(pp);}}
while(top!=0&&s[top].tag==1)top--;//退栈
if(top!=0){s[top].tag=1;bt=s[top].t->rchild;}//沿右分枝向下遍历}//结束while(bt!=null||top>0)return(null);//q、p无公共祖先}//结束Ancestor
29、证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。29.①试找出满足下列条件的二叉树
1)先序序列与后序序列相同2)中序序列与后序序列相同3)先序序列与中序序列相同4)中序序列与层次遍历序列相同
30、假设以I和O分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。(15分)
(1)A和D是合法序列,B和C是非法序列。(2)设被判定的操作序列已存入一维数组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);}}//算法结束。
31、因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。
voidLongestPath(BiTreebt)//求二叉树中的第一条最长路径长度
{BiTreep=bt,l[],s[];//l,s是栈,元素是二叉树结点指针,l中保留当前最长路径中的结点
inti,top=0,tag[],longest=0;while(p||top>0)
{while(p){s[++top]=p;tag[top]=0;p=p->Lc;}//沿左分枝向下if(tag[top]==1)//当前结点的右分枝已遍历
{if(!s[top]->Lc&&!s[top]->Rc)//只有到叶子结点时,才查看路径长度
if(top>longest){for(i=1;i<=top;i++)l[i]=s[i];longest=top;top--;}//保留当前最长路径到l栈,记住最高栈顶指针,退栈}
elseif(top>0){tag[top]=1;p=s[top].Rc;}//沿右子分枝向下
}//while(p!=null||top>0)}//结束LongestPath
32、由二叉树的前序遍历和中序遍历序列能确定唯一的一棵二叉树,下面程序的作用是实现由已知某二叉树的前序遍历和中序遍历序列,生成一棵用二叉链表表示的二叉树并打印出后序遍历序列,请写出程序所缺的语句。#defineMAX100typedefstructNode
{charinfo;structNode*llink,*rlink;}TNODE;charpred[MAX],inod[MAX];main(intargc,int**argv){TNODE*root;if(argc<3)exit0;
strcpy(pred,argv[1]);strcpy(inod,argv[2]);root=restore(pred,inod,strlen(pred));postorder(root);}
TNODE*restore(char*ppos,char*ipos,intn){TNODE*ptr;char*rpos;intk;if(n<=0)returnNULL;ptr->info=(1)_______;
for((2)_______;rpos<ipos+n;rpos++)if(*rpos==*ppos)break;k=(3)_______;
ptr->llink=restore(ppos+1,(4)_______,k);
ptr->rlink=restore((5)_______+k,rpos+1,n-1-k);returnptr;}
postorder(TNODE*ptr){if(ptr=NULL)return;
postorder(ptr->llink);postorder(ptr->rlink);printf(“%c”,ptr->info);}
33、给出折半查找的递归算法,并给出算法时间复杂度性分析。
34、本题应使用深度优先遍历,从主调函数进入dfs(v)时,开始记数,若退出dfs()前,已访问完有向图的全部顶点(设为n个),则有向图有根,v为根结点。将n个顶点从1到n编号,各调用一次dfs()过程,就可以求出全部的根结点。题中有向图的邻接表存储结构、记顶点个数的变量、以及访问标记数组等均设计为全局变量。建立有向图g的邻接表存储结构参见上面第2题,这里只给出判断有向图是否有根的算法。
intnum=0,visited[]=0//num记访问顶点个数,访问数组visited初始化。constn=用户定义的顶点数;AdjListg;
//用邻接表作存储结构的有向图g。
voiddfs(v)
{visited[v]=1;num++;//访问的顶点数+1
if(num==n){printf(“%d是有向图的根。\\n”,v);num=0;}//ifp=g[v].firstarc;while(p)
{if(visied[p->adjvex]==0)dfs(p->adjvex);p=p->next;}//while
visited[v]=0;num--;//恢复顶点v}//dfs
voidJudgeRoot()
//判断有向图是否有根,有根则输出之。{staticinti;
for(i=1;i<=n;i++)//从每个顶点出发,调用dfs()各一次。{num=0;visited[1..n]=0;dfs(i);}}//JudgeRoot
算法中打印根时,输出顶点在邻接表中的序号(下标),若要输出顶点信息,可使用g[i].vertex。
35、假设以I和O分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。(15分)
(1)A和D是合法序列,B和C是非法序列。(2)设被判定的操作序列已存入一维数组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);}}//算法结束。
36、我们可用“破圈法”求解带权连通无向图的一棵最小代价生成树。所谓“破圈法”就是“任取一圈,去掉圈上权最大的边”,反复执行这一步骤,直到没有
圈为止。请给出用“破圈法”求解给定的带权连通无向图的一棵最小代价生成树的详细算法,并用程序实现你所给出的算法。注:圈就是回路。
37、矩阵中元素按行和按列都已排序,要求查找时间复杂度为O(m+n),因此不能采用常规的二层循环的查找。可以先从右上角(i=a,j=d)元素与x比较,只有三种情况:一是A[i,j]>x,这情况下向j小的方向继续查找;二是A[i,j]<x,下步应向i大的方向查找;三是A[i,j]=x,查找成功。否则,若下标已超出范围,则查找失败。
voidsearch(datatypeA[][],inta,b,c,d,datatypex)
//n*m矩阵A,行下标从a到b,列下标从c到d,本算法查找x是否在矩阵A中.{i=a;j=d;flag=0;//flag是成功查到x的标志while(i<=b&&j>=c)if(A[i][j]==x){flag=1;break;}elseif(A[i][j]>x)j--;elsei++;
if(flag)printf(“A[%d][%d]=%d”,i,j,x);//假
定x为整型.elseprintf(“矩阵A中无%d元素”,x);}算法search结束。
[算法讨论]算法中查找x的路线从右上角开始,向下(当x>A[i,j])或向左(当x<A[i,j])。向下最多是m,向左最多是n。最佳情况是在右上角比较一次成功,最差是在左下角(A[b,c]),比较m+n次,故算法最差时间复杂度是O(m+n)。38、我们可用“破圈法”求解带权连通无向图的一棵最小代价生成树。所谓“破圈法”就是“任取一圈,去掉圈上权最大的边”,反复执行这一步骤,直到没有圈为止。请给出用“破圈法”求解给定的带权连通无向图的一棵最小代价生成树的详细算法,并用程序实现你所给出的算法。注:圈就是回路。
39、对二叉树的某层上的结点进行运算,采用队列结构按层次遍历最适宜。intLeafKlevel(BiTreebt,intk)//求二叉树bt的第k(k>1)层上叶子结点个数{if(bt==null||k<1)return(0);BiTreep=bt,Q[];//Q是队列,元素是二叉树结点指针,容量足够大intfront=0,rear=1,leaf=0;//front和rear是队头和队尾指针,leaf是叶子结点数intlast=1,level=1;Q[1]=p;//last是二叉树同层最右结点的指针,level是二叉树的层数
while(front<=rear){p=Q[++front];
if(level==k&&!p->lchild&&!p->rchild)leaf++;//叶子结点
if(p->lchild)Q[++rear]=p->lchild;//左子女入队if(p->rchild)Q[++rear]=p->rchild;//右子女入队if(front==last){level++;//二叉树同层最右结点已处理,层数增1last=rear;}//last移到指向下层最右一元素if(level>k)return(leaf);//层数大于k后退出运行
}//while}//结束LeafKLevel
40、给定n个村庄之间的交通图,若村庄i和j之间有道路,则将顶点i和j用边连接,边上的Wij表示这条道路的长度,现在要从这n个村庄中选择一个村庄建一所医院,问这所医院应建在哪个村庄,才能使离医院最远的村庄到医院的路程最短?试设计一个解答上述问题的算法,并应用该算法解答如图所示的实例。(20分)
41、证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。当n=1时,只有一个根结点,由中序序列和后序序列可以确定这棵二叉树。设当n=m-1时结论成立,现证明当n=m时结论成立。
设中序序列为S1,S2,…,Sm,后序序列是P1,P2,…,Pm。因后序序列最后一个元素Pm是根,则在中序序列中可找到与Pm相等的结点(设二叉树中各结点互不相同)Si(1≤i≤m),因中序序列是由中序遍历而得,所以Si是根结点,S1,S2,…,Si-1是左子树的中序序列,而Si+1,Si+2,…,Sm是右子树的中序序列。
若i=1,则S1是根,这时二叉树的左子树为空,右子树的结点数是m-1,则{S2,S3,…,Sm}和{P1,P2,
…,Pm-1}可以唯一确定右子树,从而也确定了二叉树。
若i=m,则Sm是根,这时二叉树的右子树为空,左子树的结点数是m-1,则{S1,S2,…,Sm-1}和{P1,P2,…,Pm-1}唯一确定左子树,从而也确定了二叉树。最后,当1<i<m时,Si把中序序列分成{S1,S2,…,Si-1}和{Si+1,Si+2,…,Sm}。由于后序遍历是“左子树—右子树—根结点”,所以{P1,P2,…,Pi-1}和{Pi,Pi+1,…Pm-1}是二叉树的左子树和右子树的后序遍历序列。因而由{S1,S2,…,Si-1}和{P1,P2,…,Pi-1}
可唯一确定二叉树的左子树,由{Si+1,Si+2,…,Sm}和{Pi,Pi+1,…,Pm-1}可唯一确定二叉树的右子树。
42、根据二叉排序树中序遍历所得结点值为增序的性质,在遍历中将当前遍历结点与其前驱结点值比较,即可得出结论,为此设全局指针变量pre(初值为null)和全局变量flag,初值为true。若非二叉排序树,则置flag为false。#definetrue1#definefalse0
typedefstructnode
{datatypedata;structnode*llink,*rlink;}*BTree;voidJudgeBST(BTreet,intflag)
//判断二叉树是否是二叉排序树,本算法结束后,在调用程序中由flag得出结论。
{if(t!=null&&flag){Judgebst(t->llink,flag);//中序遍历左子树
if(pre==null)pre=t;//中序遍历的第一个结点不必判断
elseif(pre->data<t->data)pre=t;//前驱指针指向当前结点else{flag=flase;}//不是完全二叉树
Judgebst(t->rlink,flag);//中序遍历右子树}//JudgeBST算法结束
43、根据二叉排序树中序遍历所得结点值为增序的性质,在遍历中将当前遍历结点与其前驱结点值比较,即可得出结论,为此设全局指针变量pre(初值为null)和全局变量flag,初值为true。若非二叉排序树,则置flag为false。#definetrue1#definefalse0
typedefstructnode
{datatypedata;structnode*llink,*rlink;}*BTree;voidJudgeBST(BTreet,intflag)
//判断二叉树是否是二叉排序树,本算法结束后,在调用程序中由flag得出结论。
{if(t!=null&&flag){Judgebst(t->llink,flag);//中序遍历左子树
if(pre==null)pre=t;//中序遍历的第一个结点不必判断
elseif(pre->data<t->data)pre=t;//前驱指针指向当前结点else{flag=flase;}//不是完全二叉树Judgebst(t->rlink,flag);//中序遍历右子树}//JudgeBST算法结束
44、给出折半查找的递归算法,并给出算法时间复杂度性分析。45、冒泡排序算法是把大的元素向上移(气泡的上浮),也可以把小的元素向下移(气泡的下沉)请给出上浮和下沉过程交替的冒泡排序算法。
48.有n个记录存储在带头结点的双向链表中,现用双向起泡排序法对其
按上升序进行排序,请写出这种排序的算法。(注:双向
起泡排序即相邻两趟排序向相反方向起泡)
46、对一般二叉树,仅根据一个先序、中序、后序遍历,不能确定另一个遍历序列。但对于满二叉树,任一结点的左右子树均含有数量相等的结点,根据此性质,可将任一遍历序列转为另一遍历序列(即任一遍历序列均可确定一棵二叉树)。voidPreToPost(ElemTypepre[],post[],intl1,h1,l2,h2)
//将满二叉树的先序序列转为后序序列,l1,h1,l2,h2是序列初始和最后结点的下标。
{if(h1>=l1){post[h2]=pre[l1];//根结点half=(h1-l1)/2;//左或右子树的结点数
PreToPost(pre,post,l1+1,l1+half,l2,l2+half-1)//将左子树先序序列转为后序序列PreToPost(pre,post,l1+half+1,h1,l2+half,h2-1)//将右子树先序序列转为后序序列
}}//PreToPost
32..叶子结点只有在遍历中才能知道,这里使用中序递归遍历。设置前驱结点指针pre,初始为空。第一个叶子结点由指针head指向,遍历到叶子结点时,就将它前驱的rchild指针指向它,最后叶子结点的rchild为空。LinkedListhead,pre=null;//全局变量LinkedListInOrder(BiTreebt)
//中序遍历二叉树bt,将叶子结点从左到右链成一个单链表,表头指针为head{if(bt){InOrder(bt->lchild);//中序遍历左子树
if(bt->lchild==null&&bt->rchild==null)//叶子结点if(pre==null){head=bt;pre=bt;}//处理第一个叶子结点else{pre->rchild=bt;pre=bt;}//将叶子结点链入链表InOrder(bt->rchild);//中序遍历左子树pre->rchild=null;//设置链表尾}
return(head);}//InOrder
时间复杂度为O(n),辅助变量使用head和pre,栈空间复杂度O(n)
47、请编写一个判别给定二叉树是否为二叉排序树的算法,设二叉树用llink-rlink法存储。
48、因为后序遍历栈中保留当前结点的祖先的信息,用一变量保存栈的最高栈顶指针,每当退栈时,栈顶指针高于保存最高栈顶指针的值时,则将该栈倒入辅助栈中,辅助栈始终保存最长路径长度上的结点,直至后序遍历完毕,则辅助栈中内容即为所求。
voidLongestPath(BiTreebt)//求二叉树中的第一条最长路径长度
{BiTreep=bt,l[],s[];//l,s是栈,元素是二叉树结点指针,l中保留当前最长路径中的结点
inti,top=0,tag[],longest=0;while(p||top>0)
{while(p){s[++top]=p;tag[top]=0;p=p->Lc;}//沿左分枝向下if(tag[top]==1)//当前结点的右分枝已遍历
{if(!s[top]->Lc&&!s[top]->Rc)//只有到叶子结点时,才查看路径长度
if(top>longest){for(i=1;i<=top;i++)l[i]=s[i];longest=top;top--;}//保留当前最长路径到l栈,记住最高栈顶指针,退栈}
elseif(top>0){tag[top]=1;
p=s[top].Rc;}
}//while(p!=null||top>0)}//结束LongestPath
//沿右子分枝向下
49、设有两个集合A和集合B,要求设计生成集合C=A∩B的算法,其中集合A、
B和C用链式存储结构表示。
typedefstructnode{intdata;structnode*next;}lklist;voidintersection(lklist*ha,lklist*hb,lklist*&hc){
lklist*p,*q,*t;
for(p=ha,hc=0;p!=0;p=p->next)
{for(q=hb;q!=0;q=q->next)if(q->data==p->data)break;
if(q!=0){t=(lklist*)malloc(sizeof(lklist));t->data=p->data;t->next=hc;hc=t;}}}
50、若第n件物品能放入背包,则问题变为能否再从n-1件物品中选出若干件放入背包(这时背包可放入物品的重量变为s-w[n])。若第n件物品不能放入背包,则考虑从n-1件物品选若干件放入背包(这时背包可放入物品仍为s)。若最终s=0,则有一解;否则,若s<0或虽然s>0但物品数n<1,则无解。(1)s-w[n],n-1//Knap(s-w[n],n-1)=true(2)s,n-1//Knap←Knap(s,n-1)
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- igat.cn 版权所有 赣ICP备2024042791号-1
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务