实现图的深度优先遍历

任务描述

本关任务:实现 graph.cpp 里的函数int Graph_DepthFirst(Graph*g, int start, Edge* tree)。 注意遵守约定:编号大的先进栈。

相关知识

图 2 给出了对图 1 的无向图的存储结构图:每个顶点的名称由一个字符串描述,所有字符串的起始地址组织为一个数组,数组的起始地址为vetex;顶点的相邻关系保存在相邻矩阵中,其起始地址为adjadj[i*n+j]的值为 1 表示i号顶点到j号顶点有边,为 0 表示无边,其中n是顶点个数,ij是顶点在顶点表中的编号。 将n,vetex,adj组织成结构:

  1. struct Graph {
  2. int n;//顶点数
  3. char** vetex;
  4. int* adj;
  5. };

给定指向该结构的指针g,就可以对图进行操作。

深度优先遍历算法(伪代码):

  1. DepthFirst(Graph, start)
  2. //输入Graph是图,start是开始顶点的编号
  3. //输出:tree_edge[i]=<from,to>是遍历树的一条边
  4. //tree_edge[1..n-1]为遍历树的n-1条边
  5. //tree_edge[0].to … tree_edge[n-1].to是遍历序列
  6. PUSH(<-1,start>)
  7. k=0;
  8. while(StackNotEmpty) {
  9. <a,b>=POP;
  10. if (unvisited(b)) {
  11. visit(b); //visit b, and set a flag for b.
  12. tree_edge[k++]=<a,b>; // add <a,b> to the tree
  13. for each <b,c> in the Edge Set {
  14. if (unvisited(c)) PUSH(<b,c>); //约定:编号大的先进栈
  15. }
  16. }
  17. }

对图 1 的树运行该算法的结果: 生成树的边是:{<-1,A><A,B><B,D><D,C><B,F><F,E>}; 深度优先遍历的顶点访问次序是:ABDCFE。 ####编程要求 本关任务是实现 graph.cpp 里的函数int Graph_DepthFirst(Graph*g, int start, Edge* tree)。 注意遵守约定:编号大的先进栈。

  1. //Graph.cpp
  2. ///////////////////////////////////////////////////
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "Graph.h"
  7. ////////////////////////////////////////////////////
  8. Graph* Graph_Create(int n)
  9. {
  10. Graph* g=(Graph*)malloc(sizeof(Graph));
  11. g->n=n;
  12. g->vetex=(char**)malloc(sizeof(char*)*n);
  13. int i;
  14. for (i=0; i<n; i++) g->vetex[i] = NULL;
  15. g->adj=(int*)malloc(sizeof(int)*n*n);
  16. int j;
  17. for(i=0; i<n; i++) {
  18. for(j=0; j<n; j++) {
  19. g->adj[i*n+j]=0;
  20. }
  21. }
  22. return g;
  23. }
  24. void Graph_Free(Graph* g)
  25. {
  26. free(g->adj);
  27. int i;
  28. for (i=0; i<g->n; i++) free(g->vetex[i]);
  29. free(g->vetex);
  30. free(g);
  31. }
  32. int Graph_DepthFirst(Graph*g, int start, Edge* tree)
  33. //从start号顶点出发深度优先遍历,(编号从0开始)
  34. //返回访问到的顶点数,
  35. //tree[]输出遍历树
  36. //返回的tree[0]是(-1, start),
  37. //真正的遍历树保存在tree[1..return-1], return是返回值
  38. //顶点的访问次序依次为tree[0].to, tree[1].to, ..., tree[return-1].to
  39. //输入时,tree[]的长度至少为顶点数
  40. //返回值是从start出发访问到的顶点数
  41. {
  42. //在begin和end之间添加你的代码
  43. /*****begin*****/
  44. /*****end*******/
  45. }
测试说明

本关的测试过程如下:

  1. 平台编译 step2/Main.cpp ;
  2. 平台运行该可执行文件,并以标准输入方式提供测试输入;
  3. 平台获取该可执行文件的输出,然后将其与预期输出对比,如果一致则测试通过;否则测试失败。

输入输出格式:

输入格式: 输入n,顶点数 输入n个字符串,即n个顶点的名称,其编号按输入次序是:0,...,n-1。 输入若干数字对(a b)或<a b>(a b)表示无向边,<a b>表示有向边 输入字符x,表示边输入结束 输入一个数start,表示开始顶点的编号

输出格式: 输出生成树的边序列,边的第start个顶点构成的序列应是顶点访问序列

以下是平台对 step2/Main.cpp 的测试样例: 样例输入

  1. 6
  2. A
  3. B
  4. C
  5. D
  6. E
  7. F
  8. ( 0 1 )
  9. ( 0 2 )
  10. ( 0 5 )
  11. ( 1 3 )
  12. ( 1 5 )
  13. ( 2 3 )
  14. ( 4 5 )
  15. x
  16. 0

样例输出

  1. tree edges: <-1,A> <A,B> <B,D> <D,C> <B,F> <F,E>
  2. visit sequence: A B D C F E

//Graph
///////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Graph.h"
/////////////////////////////////////////////////////////////
Graph* Graph_Create(int n)
{
	Graph* g=(Graph*)malloc(sizeof(Graph));
	g->n=n;
	g->vetex=(char**)malloc(sizeof(char*)*n);
	int i;
	for (i=0; i<n; i++) g->vetex[i] = NULL;
	g->adj=(int*)malloc(sizeof(int)*n*n);
	int j;
	for(i=0; i<n; i++) {
		for(j=0; j<n; j++) {
			g->adj[i*n+j]=0;
		}
	}
	return g;
}

void Graph_Free(Graph* g)
{
	free(g->adj);
	int i;
	for (i=0; i<g->n; i++) free(g->vetex[i]);
	free(g->vetex);
	free(g);
}

int Graph_DepthFirst(Graph*g, int start, Edge* tree)
//从start号顶点出发深度优先遍历,(编号从开始)
//返回访问到的顶点数,
//tree[]输出遍历树
//返回的tree[0]是(-1, start), 
//真正的遍历树保存在tree[1..return-1], return是返回值
//顶点的访问次序依次为tree[0].to, tree[1].to, ..., tree[return-1].to
//输入时,tree[]的长度至少为顶点数
//返回值是从start出发访问到的顶点数
{
	/*请在BEGIN和END之间实现你的代码*/
    /*****BEGIN*****/
     const int MAX=1000;
	Edge queue[MAX];
	int head=0, tail=0;
#define In__(a,b)  {tail=tail+1; queue[tail].from=a; queue[tail].to=b;}/////////
#define Out__(a,b)  {a=queue[tail].from; b=queue[tail].to; tail=tail-1;}//
#define QueueNotEmpty (head!=tail?1:0)///////////////////////////////////
#define HasEdge(i,j)  (g->adj[(i)*g->n+(j)]==1)

	char* visited=(char*)malloc(sizeof(char)*g->n);
	memset(visited, 0, sizeof(char)*g->n);

	int parent=-1;  
	int curr=start;
	In__(parent, curr); 
	int k=0;
    while(QueueNotEmpty)
    {
    	Out__(parent, curr); 
    	if((HasEdge(parent, curr)||parent==-1)&&visited[curr]!=1)
    	{
			visited[curr]=1;
			tree[k].from=parent;
    		tree[k].to=curr;
    		k++;
			for(int i=g->n-1;i>=0;i--)
    			if(HasEdge(curr,i)&&visited[i]!=1)
    				In__(curr,i);
		}	
	}
	return k;
#undef In__//////////////////////////////
#undef Out__///////////////////////////////
#undef QueueNotEmpty////////////////////////
#undef HasEdge
    /*****END*******/
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式Dora

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值