数据结构--------图的遍历算法及实现

来源:互联网 发布:java ee看源代码 编辑:程序博客网 时间:2024/06/07 06:12

经过俩天的学习,现在终于明白了图的遍历算法。图的遍历是指从图中的任一顶点出发,对图中的所有顶点访问且只访问一次的过程。图的遍历是图的一种基本操作,图的其他算法如求解图的拓扑排序、关键路径等都是在遍历算法的基础上实现的。因此弄清楚图的遍历算法极其关键。

由于图结构本身的复杂性,所以图的遍历操作也较复杂,主要表现在以下四个方面:
① 在图结构中,没有一个“自然”的首结点,图中任意一个顶点都可作为第一个被访问的结点。
② 在非连通图中,从一个顶点出发,只能够访问它所在的连通分量上的所有顶点,因此,还需考虑如何选取下一个出发点以访问图中其余的连通分量。
③ 在图结构中,如果有回路存在,那么一个顶点被访问之后,有可能沿回路又回到该顶点。

④ 在图结构中,一个顶点可以和其它多个顶点相连,当这样的顶点访问过后,存在如何选取下一个要访问的顶点的问题。

图的遍历通常有深度优先搜索和广度优先搜索两种方式,他们对无向图和有向图都适用。

1、深度优先遍历递归算法

(1)首先访问节点K,如果节点K未被访问,则标记visited[k]=1并输出节点k的数据信息;

(2)查找与节点k相连的下一个节点i,如果存在且未被访问,则递归调用;接着查找与节点k相连且与节点i相邻的节点,更新i的值,直到与k相连的节点查找完毕。

2、广度优先遍历(利用队列)算法

假设从图中某顶点v 出发,在访问了v 之后依次访问v 的各个未曾访问过和邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的顶点的邻接点都被访问到。若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止。换句话说,广度优先搜索遍历图的过程中以v 为起始点,由近至远,依次访问和v 有路径相通且路径长度为1,2,…的顶点。



/*无向图的邻接矩阵表示*/#include<stdlib.h>#include<stdio.h>#include<malloc.h>#define MAX_VERX 20  /*最大节点数*/#define INFINITY 32767#define DataType charint *visited=NULL;struct _node  /* 定义队列节点 */{int v_num;struct _node *next;};typedef   struct _node  node,*pnode;struct _queue  /*队列数据结构*/{pnode front;pnode rear;};   typedef struct _queue  queue,*pqueue;struct _graph  /*图的数据结构*/{DataType *vexs;int arcs[MAX_VERX][MAX_VERX];int vexnum;int arcnum;};typedef struct _graph graph,*pgraph;/*队列的操作*/queue Init_Queue()  /*队列初始化*/{queue qu;qu.front=qu.rear=(pnode)malloc(sizeof(node));if(qu.front==NULL)exit(1);qu.rear->next=NULL;return qu;}int isempty_queue(pqueue pqu)  /*判断队列是否为空*/{if(pqu->front==pqu->rear)return 1;elsereturn 0;}void  en_queue(pqueue pqu,int v_num) /*进队列*/{pnode pn;pn=(pnode)malloc(sizeof(node));if(pqu->front==NULL)exit(1);pn->v_num=v_num;pn->next=NULL;pqu->rear->next=pn;pqu->rear=pqu->rear->next;}int  de_queue(pqueue pqu)  /*出队列*/{pnode pn;int d;if(isempty_queue(pqu))return -1;pn=pqu->front;   d=pn->next->v_num;      //出队列时要找到队列顶部的下一节点pqu->front=pqu->front->next;free(pn);return d;}int islocate(pgraph pg,DataType ch){DataType *dt;int i;dt=pg->vexs;for(i=0;i<pg->vexnum;i++){if(ch==dt[i])return i;}return -1;}//图的基本操作graph create_graph(){int i,j,s1,s2;float w;char ch1,ch2,temp;graph g;printf("请输入顶点数和边数:");scanf("%d %d",&g.vexnum,&g.arcnum);temp=getchar();printf("请输入%d顶点信息\n",g.vexnum);g.vexs=(DataType*)malloc(g.vexnum*sizeof(DataType));for(i=0;i<g.vexnum;i++){//printf("vex[%d]: ",i);scanf("%c",&g.vexs[i]);temp=getchar();}/*for(i=0;i<g.vexnum;i++)   //检查输入定点信息是否正确{printf("vex[%d]: %c\n",i,g.vexs[i]);}*/for(i=0;i<g.vexnum;i++)  //初始化边值信息for(j=0;j<g.vexnum;j++){g.arcs[i][j]=INFINITY;}printf("请输入%d条边\n",g.arcnum);for(i=0;i<g.arcnum;i++){printf("请输入边%d的信息(俩边顶点权值)",i);scanf("%c %c %f",&ch1,&ch2,&w);temp=getchar();s1=islocate(&g,ch1);s2=islocate(&g,ch2);g.arcs[s1][s2]=g.arcs[s2][s1]=w;}return g;}/* 查找与顶点k相连的第一个顶点*/int firstvex_graph(graph g,int k){int j;if(k>=0&&k<g.vexnum){for(j=0;j<g.vexnum;j++){if(g.arcs[k][j]!=INFINITY)return j;}}return -1; //查找失败}/*查找与顶点i相连且在顶点j下一个的顶点*/int nextvex_graph(graph g,int i,int j){int k;if(i>=0&&i<g.vexnum&&j>=0&&j<g.vexnum){for(k=j+1;k<g.vexnum;k++){if(g.arcs[i][k]!=INFINITY)return k;}}return -1;//查找相邻节点失败}/*从顶点k开始深度优先遍历图*/void  dfs(graph g,int k){int i;if(k==-1){for(i=0;i<g.vexnum;i++){if(!visited[i])dfs(g,i);}}else{    visited[k]=1;printf("%c ",g.vexs[k]);for(i=firstvex_graph(g,k);i>=0;i=nextvex_graph(g,k,i))if(!visited[i]){dfs(g,i);}}}/* 从顶点k开始广度优先遍历图 */void bfs(graph g){int i,j,k;queue qu=Init_Queue();for(i=0;i<g.vexnum;i++){if(!visited[i]){visited[i]=1;printf("%c",g.vexs[i]);en_queue(&qu,i);while(!isempty_queue(&qu)){k=de_queue(&qu);for(j=firstvex_graph(g,k);j>=0;j=nextvex_graph(g,k,j)){if(!visited[j]){visited[j]=1;printf("%c",g.vexs[j]);en_queue(&qu,j);}}}}}}int main(){int i,k=-1;graph g=create_graph();visited=(int*)malloc(g.vexnum*sizeof(int));if(visited==NULL){printf("错误!!!!!!!!!!!");}for(i=0;i<g.vexnum;i++){visited[i]=0;}printf("\n\n*******************d f s***************\n");dfs(g,k);for(i=0;i<g.vexnum;i++){visited[i]=0;}printf("\n*******************b f s***************\n");bfs(g);return 1;}





0 0
原创粉丝点击