数据结构复习题(附答案) 下载本文

内容发布更新时间 : 2024/5/21 1:21:25星期一 下面是文章的全部内容请认真阅读。

S2 S1 S3 S1 S4 S1 S6 S5 S1 S5 S1 S1

①分别求出str1、str2的长度m、n

②将两个链表的表尾对齐。p、q两个指针。

③p、q两个指针同步移动,直到指向相同结点。

先将n个数据(前后对应交换)原地逆置,然后再将前n-p和后p个分别原地逆置。 Void reverse(int r[], int left, int right) {

int k=left, j=right, temp; while (k

temp=r[k]; r[k]=r[j]; r[j]=temp; k++;j--; } }

Void leftshift(int r[], int n, int p) {

if(p>0&&p

{ reverse(r,0,n-1);reverse(r,0,n-p-1);reverse(r,n-p,n-1);} } 4. [题目分析]题目中要求矩阵两行元素的平均值按递增顺序排序,由于每行元素个数相等,按平均值排列与按每行元素之和排列是一个意思。所以应先求出各行元素之和,放入一维数组中,然后选择一种排序方法,对该数组进行排序,注意在排序时若有元素移动,则与之相应的行中各元素也必须做相应变动。

void Translation(float *matrix,int n)

//本算法对n×n的矩阵matrix,通过行变换,使其各行元素的平均值按递增排列。 {int i,j,k,l;

float sum,min; //sum暂存各行元素之和 float *p, *pi, *pk; for(i=0; i

{sum=0.0; pk=matrix+i*n; //pk指向矩阵各行第1个元素.

for (j=0; j

*(p+i)=sum; //将一行元素之和存入一维数组.

}//for i

for(i=0; i

for(j=i+1;j

{pk=matrix+n*k; //pk指向第k行第1个元素. pi=matrix+n*i; //pi指向第i行第1个元素. for(j=0;j

{sum=*(pk+j); *(pk+j)=*(pi+j); *(pi+j)=sum;}

sum=p[i]; p[i]=p[k]; p[k]=sum; //交换一维数组中元素之和. }//if }//for i

free(p); //释放p数组. }// Translation

[算法分析] 算法中使用选择法排序,比较次数较多,但数据交换(移动)较少.若用其它

2

排序方法,虽可减少比较次数,但数据移动会增多.算法时间复杂度为O(n). 7.[题目分析]我们用l代表最长平台的长度,用k指示最长平台在数组b中的起始位置(下标)。用j记住局部平台的起始位置,用i指示扫描b数组的下标,i从0开始,依次和后续元素比较,若局部平台长度(i-j)大于l时,则修改最长平台的长度k(l=i-j)和其在b中的起始位置(k=j),直到b数组结束,l即为所求。

void Platform (int b[ ], int N)

//求具有N个元素的整型数组b中最长平台的长度。 {l=1;k=0;j=0;i=0; while(i

{while(i

if(i-j+1>l) {l=i-j+1;k=j;} //局部最长平台 i++; j=i; } //新平台起点

printf(“最长平台长度%d,在b数组中起始下标为%d”,l,k); }// Platform

8.[题目分析]矩阵中元素按行和按列都已排序,要求查找时间复杂度为O(m+n),因此不能采用常规的二层循环的查找。可以先从右上角(i=a,j=d)元素与x比较,只有三种情况:一是A[i,j]>x, 这情况下向j 小的方向继续查找;二是A[i,j]

void search(datatype A[ ][ ], int a,b,c,d, datatype x)

//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;}

else if (A[i][j]>x) j--; else i++;

if(flag) printf(“A[%d][%d]=%d”,i,j,x); //假定x为整型. else printf(“矩阵A中无%d 元素”,x); }算法search结束。

[算法讨论]算法中查找x的路线从右上角开始,向下(当x>A[i,j])或向左(当x

22、[题目分析]数组A和B的元素分别有序,欲将两数组合并到C数组,使C仍有序,应将A和B拷贝到C,只要注意A和B数组指针的使用,以及正确处理一数组读完数据后将另一数组余下元素复制到C中即可。

void union(int A[],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=0)

if(a[i]=0) c[k++]=b[j--]; }算法结束

4、要求二叉树按二叉链表形式存储。15分

(1)写一个建立二叉树的算法。(2)写一个判别给定的二叉树是否是完全二叉树的算法。

BiTree Creat() //建立二叉树的二叉链表形式的存储结构 {ElemType x;BiTree bt;

scanf(“%d”,&x); //本题假定结点数据域为整型 if(x==0) bt=null; else if(x>0)

{bt=(BiNode *)malloc(sizeof(BiNode));

bt->data=x; bt->lchild=creat(); bt->rchild=creat(); }

else error(“输入错误”); return(bt); }//结束 BiTree

int JudgeComplete(BiTree bt) //判断二叉树是否是完全二叉树,如是,返回1,否则,返回0

{int tag=0; BiTree p=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) return 0; //前边已有结点为空,

本结点不空

else tag=1; //首次出现结点为空 if (p->rchild && !tag) QueueIn(Q,p->rchild); //右子女入队 else if (p->rchild) return 0; else tag=1; } //while

return 1; } //JudgeComplete

3、已知一棵二叉树的中序遍历结果为:DBFEAGHCI,后序遍历结果为:DFEBHGICA。 (1)画出这棵二叉树,并写出它的前序遍历结果; (2)将这棵二叉树转换成等价的森林或树。 前序遍历结果为:ABDEFCGHI

24. (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->lchild

27. (1)*ppos // 根结点 (2)rpos=ipos (3)rpos–ipos (4)ipos (5)ppos+1

28. 证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。

当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

可唯一确定二叉树的左子树,由{Si+1,Si+2,?,Sm}和 {Pi,Pi+1,?,Pm-1}可唯一确定二叉树的右子树 。

29. 原则,本题解答如下:

(1) 若先序序列与后序序列相同,则或为空树,或为只有根结点的二叉树

(2) 若中序序列与后序序列相同,则或为空树,或为任一结点至多只有左子树的二叉树. (3) 若先序序列与中序序列相同,则或为空树,或为任一结点至多只有右子树的二叉树. (4) 若中序序列与层次遍历序列相同,则或为空树,或为任一结点至多只有右子树的二

叉树。

30. .[题目分析]后序遍历最后访问根结点,即在递归算法中,根是压在栈底的。采用后序非递归算法,栈中存放二叉树结点的指针,当访问到某结点时,栈中所有元素均为该结点的祖先。本题要找p和q 的最近共同祖先结点r ,不失一般性,设p在q的左边。后序遍历必然先遍历到结点p,栈中元素均为p的祖先。将栈拷入另一辅助栈中。再继续遍历到结点q时,将栈中元素从栈顶开始逐个到辅助栈中去匹配,第一个匹配(即相等)的元素就是结点p 和q的最近公共祖先。 typedef struct

{BiTree t;int tag;//tag=0 表示结点的左子女已被访问,tag=1表示结点的右子女已被访问 }stack;

stack s[],s1[];//栈,容量够大

BiTree Ancestor(BiTree ROOT,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

31. .[题目分析]对一般二叉树,仅根据一个先序、中序、后序遍历,不能确定另一个遍历序列。但对于满二叉树,任一结点的左右子树均含有数量相等的结点,根据此性质,可将任一遍历序列转为另一遍历序列(即任一遍历序列均可确定一棵二叉树)。

void PreToPost(ElemType pre[] ,post[],int l1,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) //将左子树先序序列转为后序序列