2015青海省C语言版入门
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1、 假设以邻接矩阵作为图的存储结构, 编写算法判别在给定的有向图中是否存在一个简单有 向回路,若存在,则以顶点序列的方式输出该回路(找到一条即可) 。 (注:图中不存在顶点 到自己的弧) 有向图判断回路要比无向图复杂。利用深度优先遍历,将顶点分成三类:未访问;已访问但 其邻接点未访问完;已访问且其邻接点已访问完。下面用 0,1,2 表示这三种状态。前面已提 到,若 dfs(v)结束前出现顶点 u 到 v 的回边,则图中必有包含顶点 v 和 u 的回路。对应程 序中 v 的状态为 1,而 u 是正访问的顶点,若我们找出 u 的下一邻接点的状态为 1,就可以输 出回路了。 void Print(int v,int start ) //输出从顶点 start 开始的回路。 {for(i=1;i<=n;i++) if(g[v][i]!=0 && visited[i]==1 ) //若存在边(v,i) ,且顶点 i 的状态为 1。 {printf(“%d”,v); if(i==start) printf(“\n”); else Print(i,start);break;}//if }//Print void dfs(int v) {visited[v]=1; for(j=1;j<=n;j++ ) if (g[v][j]!=0) //存在边(v,j) if (visited[j]!=1) {if (!visited[j]) dfs(j); }//if else {cycle=1; Print(j,j);} visited[v]=2; }//dfs void find_cycle() //判断是否有回路,有则输出邻接矩阵。visited 数组为全局变量。 {for (i=1;i<=n;i++) visited[i]=0; for (i=1;i<=n;i++ ) if (!visited[i]) dfs(i); }//find_cycle 2、 我们可用 “破圈法” 求解带权连通无向图的一棵最小代价生成树。 所谓 “破圈法” 就是 “任 取一圈,去掉圈上权最大的边” ,反复执行这一步骤,直到没有圈为止。请给出用“破圈法” 求解给定的带权连通无向图的一棵最小代价生成树的详细算法,并用程序实现你所给出的算 法。注:圈就是回路。 3、假设以 I 和 O 分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列 可表示为仅由 I 和 O 组成的序列,称可以操作的序列为合法序列,否则称为非法序列。 (15 分) (1)下面所示的序列中哪些是合法的? A. IOIIOIOO B. IOOIOIIO C. IIIOIOIO D. IIIOOIOO (2)通过对(1)的分析,写出一个算法,判定所给的操作序列是否合法。若合法,返回 true,否则返回 false(假定被判定的操作序列已存入一维数组中) 。 4、有一个带头结点的单链表,每个结点包括两个域,一个是整型域 info,另一个是指向下 一个结点的指针域 next。假设单链表已建立,设计算法删除单链表中所有重复出现的结点, 使得 info 域相等的结点只保留一个。 #include <stdio.h> typedef char datatype;
{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 6、假设以 I 和 O 分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列 可表示为仅由 I 和 O 组成的序列,称可以操作的序列为合法序列,否则称为非法序列。 (15 分) (1)下面所示的序列中哪些是合法的? A. IOIIOIOO B. IOOIOIIO C. IIIOIOIO D. IIIOOIOO (2)通过对(1)的分析,写出一个算法,判定所给的操作序列是否合法。若合法,返回 true,否则返回 false(假定被判定的操作序列已存入一维数组中) 。 7、本题应使用深度优先遍历,从主调函数进入 dfs(v)时 ,开始记数,若退出 dfs()前,已 访问完有向图的全部顶点(设为 n 个) ,则有向图有根,v 为根结点。将 n 个顶点从 1 到 n 编 号,各调用一次 dfs()过程,就可以求出全部的根结点。题中有向图的邻接表存储结构、记 顶点个数的变量、以及访问标记数组等均设计为全局变量。建立有向图 g 的邻接表存储结构 参见上面第 2 题,这里只给出判断有向图是否有根的算法。 int num=0, visited[]=0 //num 记访问顶点个数,访问数组 visited 初始化。 const n=用户定义的顶点数; AdjList g ; //用邻接表作存储结构的有向图 g。 void dfs(v) {visited [v]=1; num++; //访问的顶点数+1 if (num==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 void JudgeRoot() //判断有向图是否有根,有根则输出之。 {static int i ; for (i=1;i<=n;i++ ) //从每个顶点出发,调用 dfs()各一次。 {num=0; visited[1..n]=0; dfs(i); } }// JudgeRoot
}算法结束 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 11、给定 n 个村庄之间的交通图,若村庄 i 和 j 之间有道路,则将顶点 i 和 j 用边连接,边 上的 Wij 表示这条道路的长度,现在要从这 n 个村庄中选择一个村庄建一所医院,问这所医 院应建在哪个村庄, 才能使离医院最远的村庄到医院的路程最短?试设计一个解答上述问题的 算法,并应用该算法解答如图所示的实例。 (20 分) 12、证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。 当 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}唯一确定左子树,从而也确定了二叉树。
源自文库
算法中打印根时,输出顶点在邻接表中的序号(下标) ,若要输出顶点信息,可使 用 g[i].vertex。
8、本题要求建立有序的循环链表。从头到尾扫描数组 A,取出 A[i](0<=i<n),然后到链表 中去查找值为 A[i]的结点,若查找失败,则插入。 LinkedList creat(ElemType A[],int n) //由含 n 个数据的数组 A 生成循环链表,要求链表有序并且无值重复结点 {LinkedList h; h=(LinkedList)malloc(sizeof(LNode));//申请结点 h->next=h; //形成空循环链表 for(i=0;i<n;i++) {pre=h; p=h->next; while(p!=h && p->data<A[i]) {pre=p; p=p->next;} //查找 A[i]的插入位置 if(p==h || p->data!=A[i]) //重复数据不再输入 {s=(LinkedList)malloc(sizeof(LNode)); s->data=A[i]; pre->next=s; s->next=p;//将结点 s 链入链表中 } }//for return(h); }算法结束 9 、 (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 10、数组 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<m && j>=0) if(a[i]<b[j]) c[k++]=a[i++] else c[k++]=b[j--]; while(i<m) c[k++]=a[i++]; while(j>=0) c[k++]=b[j--];
typedef struct node{ datatype data; struct node * next; } listnode; typedef listnode* linklist; /*--------------------------------------------*/ /* 删除单链表中重复的结点 */ /*--------------------------------------------*/ linklist deletelist(linklist head) { 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; } return head; } 5、后序遍历最后访问根结点,即在递归算法中,根是压在栈底的。采用后序非递归算法,栈 中存放二叉树结点的指针,当访问到某结点时,栈中所有元素均为该结点的祖先。本题要找 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 6、假设以 I 和 O 分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列 可表示为仅由 I 和 O 组成的序列,称可以操作的序列为合法序列,否则称为非法序列。 (15 分) (1)下面所示的序列中哪些是合法的? A. IOIIOIOO B. IOOIOIIO C. IIIOIOIO D. IIIOOIOO (2)通过对(1)的分析,写出一个算法,判定所给的操作序列是否合法。若合法,返回 true,否则返回 false(假定被判定的操作序列已存入一维数组中) 。 7、本题应使用深度优先遍历,从主调函数进入 dfs(v)时 ,开始记数,若退出 dfs()前,已 访问完有向图的全部顶点(设为 n 个) ,则有向图有根,v 为根结点。将 n 个顶点从 1 到 n 编 号,各调用一次 dfs()过程,就可以求出全部的根结点。题中有向图的邻接表存储结构、记 顶点个数的变量、以及访问标记数组等均设计为全局变量。建立有向图 g 的邻接表存储结构 参见上面第 2 题,这里只给出判断有向图是否有根的算法。 int num=0, visited[]=0 //num 记访问顶点个数,访问数组 visited 初始化。 const n=用户定义的顶点数; AdjList g ; //用邻接表作存储结构的有向图 g。 void dfs(v) {visited [v]=1; num++; //访问的顶点数+1 if (num==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 void JudgeRoot() //判断有向图是否有根,有根则输出之。 {static int i ; for (i=1;i<=n;i++ ) //从每个顶点出发,调用 dfs()各一次。 {num=0; visited[1..n]=0; dfs(i); } }// JudgeRoot
}算法结束 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 11、给定 n 个村庄之间的交通图,若村庄 i 和 j 之间有道路,则将顶点 i 和 j 用边连接,边 上的 Wij 表示这条道路的长度,现在要从这 n 个村庄中选择一个村庄建一所医院,问这所医 院应建在哪个村庄, 才能使离医院最远的村庄到医院的路程最短?试设计一个解答上述问题的 算法,并应用该算法解答如图所示的实例。 (20 分) 12、证明由二叉树的中序序列和后序序列,也可以唯一确定一棵二叉树。 当 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}唯一确定左子树,从而也确定了二叉树。
源自文库
算法中打印根时,输出顶点在邻接表中的序号(下标) ,若要输出顶点信息,可使 用 g[i].vertex。
8、本题要求建立有序的循环链表。从头到尾扫描数组 A,取出 A[i](0<=i<n),然后到链表 中去查找值为 A[i]的结点,若查找失败,则插入。 LinkedList creat(ElemType A[],int n) //由含 n 个数据的数组 A 生成循环链表,要求链表有序并且无值重复结点 {LinkedList h; h=(LinkedList)malloc(sizeof(LNode));//申请结点 h->next=h; //形成空循环链表 for(i=0;i<n;i++) {pre=h; p=h->next; while(p!=h && p->data<A[i]) {pre=p; p=p->next;} //查找 A[i]的插入位置 if(p==h || p->data!=A[i]) //重复数据不再输入 {s=(LinkedList)malloc(sizeof(LNode)); s->data=A[i]; pre->next=s; s->next=p;//将结点 s 链入链表中 } }//for return(h); }算法结束 9 、 (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 10、数组 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<m && j>=0) if(a[i]<b[j]) c[k++]=a[i++] else c[k++]=b[j--]; while(i<m) c[k++]=a[i++]; while(j>=0) c[k++]=b[j--];
typedef struct node{ datatype data; struct node * next; } listnode; typedef listnode* linklist; /*--------------------------------------------*/ /* 删除单链表中重复的结点 */ /*--------------------------------------------*/ linklist deletelist(linklist head) { 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; } return head; } 5、后序遍历最后访问根结点,即在递归算法中,根是压在栈底的。采用后序非递归算法,栈 中存放二叉树结点的指针,当访问到某结点时,栈中所有元素均为该结点的祖先。本题要找 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 的祖先结点