C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)
2016-12-24 09:22
459 查看
上一篇主要讲了二叉树的先序,中序,后序遍历算法以及深度和节点的算法,这篇就讲一讲图的基本算法。
特点:由上述可知,无向图或网络的邻接矩阵是对称的。并且,该法比较简单,用一个二维数组就可存储。
缺点:浪费空间,可用处理“稀疏”矩阵的方式去处理。
在边少的情况下,用邻接表比邻接矩阵节省存储空间。
上图遍历结果为:V1 --> V2 --> V4 --> V8 --> V5 --> V3 --> V6 --> V7
上图遍历结果为:V1 --> V2 --> V3 --> V4 --> V5 --> V6 --> V7 --> V8
1)设A[1..n,1..n]为有向图的带权邻接矩阵,A[i,j]表示弧(Vi,Vj)上的权值,若(Vi,Vj)不存在,则A[i,j]为无穷大;S 为已找到从源点V0出发的最短路径的终点集合,初始状态为{V0};DIST[1..n]为个终点当前找到的最短路径长度,初始值为DIST[i]=A[V0,i];
2)选择u,使DIST[u]=min{DIST[w]|w!∈S,w∈V}, S=S∪{u},其中,V为有向图的顶点集合;
3)对于所有不在S中终点w,若 DIST[u]+A[u,w] < DIST[w], 则修改DIST[w]为 DIST[w]=DIST[u]+A[u,w];
4)重复操作2)、3)共n-1次,由此可求得从V0到各终点的最短路径。
V1Þ V2ÞV3Þ V4ÞV5ÞV6ÞV7ÞV8
一、图的基本概念
1.1有向图G1:
有向图G是由两个集合V(G)和E(G)组成的,其中:V(G)是顶点的非空有限集,E(G)是有向边(也称弧)的有限集合,弧是顶点的有序对,记为<v,w>,v,w是顶点,v为弧尾,w为弧头,(v,w)!=(w,v)。1.2无向图G2:
无向图G是由两个集合V(G)和E(G)组成的,其中:V(G)是顶点的非空有限集,E(G)是边的有限集合,边是顶点的无序对,记为(v,w)或(w,v),并且(v,w)=(w,v)。二、图的存储结构(以无向图G1为例)
2.1邻接矩阵(关联矩阵、关系矩阵)
特点:由上述可知,无向图或网络的邻接矩阵是对称的。并且,该法比较简单,用一个二维数组就可存储。缺点:浪费空间,可用处理“稀疏”矩阵的方式去处理。
2.2邻接表G1
邻接表是图的一种链式存储结构。在邻接表中,对图中的每个结点建立一个单链表。第i个单链表中的结点表示依附于顶点Vi的边(有向图中指以Vi为尾的弧).在边少的情况下,用邻接表比邻接矩阵节省存储空间。
三、图的遍历
3.1深度优先遍历
从图的某一顶点V0出发,访问此顶点;然后依次从V0的未被访问的邻接点出发,深度优先遍历图,直至图中所有和V0相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。上图遍历结果为:V1 --> V2 --> V4 --> V8 --> V5 --> V3 --> V6 --> V7
3.2广度优先遍历
从图的某一顶点V0出发,访问此顶点后,依次访问V0的各个未曾访问过的邻接点;然后分别从这些邻接点出发,广度优先遍历图,直至图中所有已被访问的顶点的邻接点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。上图遍历结果为:V1 --> V2 --> V3 --> V4 --> V5 --> V6 --> V7 --> V8
四、迪杰斯特拉算法求单源最短路径(Dijkstra)
算法描述;1)设A[1..n,1..n]为有向图的带权邻接矩阵,A[i,j]表示弧(Vi,Vj)上的权值,若(Vi,Vj)不存在,则A[i,j]为无穷大;S 为已找到从源点V0出发的最短路径的终点集合,初始状态为{V0};DIST[1..n]为个终点当前找到的最短路径长度,初始值为DIST[i]=A[V0,i];
2)选择u,使DIST[u]=min{DIST[w]|w!∈S,w∈V}, S=S∪{u},其中,V为有向图的顶点集合;
3)对于所有不在S中终点w,若 DIST[u]+A[u,w] < DIST[w], 则修改DIST[w]为 DIST[w]=DIST[u]+A[u,w];
4)重复操作2)、3)共n-1次,由此可求得从V0到各终点的最短路径。
五、代码分析
把基本概念讲解后,我们来看看代码的实现,注释都比较清楚,我就不一一讲解了#include <stdio.h> #include <malloc.h> #define MAX 1000//表示两顶点间无连接 #define VN 5//顶点数 typedef struct GLink GLink; /* 初始化邻接矩阵(图) */ int G[VN][VN] = { 0,9,6,3,MAX, 9,0,4,5,MAX, 6,4,0,MAX,7, 3,5,MAX,0,8, MAX,MAX,7,8,MAX }; /* 邻接表的node */ struct GLink{ int adjvex;//下标 int weight;//权值 GLink *next;//邻接表node的下一个顶点 }; GLink *GL[VN];/*存储所有的顶点*/ int visit[VN];/*存储已经遍历的顶点*/ /* 将上面的邻接矩阵转化为邻接表 */ void createGLink(int G[VN][VN]){ int i,j; GLink *q,*p; for(i = 0;i<VN;i++){ GL[i] = q =NULL; for(j = 0;j < VN ;j++){ if((i != j) && ( G[i][j] > 0) && (G[i][j] < MAX)){ //存在有效路径 p = (GLink * ) malloc(sizeof( GLink)); p->adjvex = j;/*获取顶点的下标*/ p->weight = G[i][j];/*获取顶点的权值*/ if(NULL==GL[i]) GL[i] = p; else q->next = p; q = p; } } q->next = NULL; } } /* 深度遍历优先 */ void DFS(GLink *G[VN],int v){ GLink *p; p = G[v]; printf("[ %d ] ",(v+1)); visit[v] = 1; while(NULL != p){ //printf("第 %d 个顶点 到第 %d 个顶点的权值为: %d \n",(v+1),(p->adjvex + 1),p->weight); if ((visit[p->adjvex] != 1)){ DFS(G,p->adjvex); } p = p->next; } //printf(" 第 %d 个顶点完成遍历\n ",(v+1)); } /* 广度遍历优先 */ void BFS(GLink *G[VN],int v){ int i,n = 0;//n 是获取队列中的顶点 GLink *p; int Q[VN];//存放已经访问过的顶点 //初始化队列 for(i = 0;i < VN;i++){ Q[i] = MAX; } visit[v] = 1; Q[0] = v; int k = 1;//当前队列中的顶点数 printf("[ %d ] ",(v+1)); while((k<VN) && (n<i)){ p = G[Q ];//找到当前顶点边表链表头指针 n++; while(NULL != p){ //printf("第 %d 个顶点 到第 %d 个顶点的权值为: %d \n",(v+1),(p->adjvex + 1),p->weight); if(visit[p->adjvex] != 1){ printf("[ %d ] ",(p->adjvex+1)); //将访问过的顶点入队 Q[k] = p->adjvex; //修改为访问过 visit[p->adjvex] = 1; k++; } p = p->next; } } } /* 根据Dijkstra算法求出单元最短路径 v是起始点 */ void Short(int G[VN][VN],int v){ int Dist[VN];//两点之间的最短距离 int Path[VN];//存储的路径 int final[VN];//已经找到的最短路径顶点 int i ,j ;//外部和内部循环 /* 存储v顶点到其他顶点之间的距离,默认为这两点之间的最短距离 */ for(i = 0; i < VN ; i++){ final[i] = 0;//将final初始化,表示没有一个顶点找到了最短路径 Dist[i] = G[v][i];//存储距离 if(Dist[i] < MAX) Path[i] = v;//v点到i点的路径有效,存储该路径v } final[v] = 1;//标记为最短路径 int min,k; for(i = 0;i < VN;i++){ min = MAX;//获取最短路径 k = v; //获取距离v点最短的顶点 for(j = 0;j < VN ; j++){ //v -> i 如果存在有效路径,并且小于当前的最小距离 if( (final[i] != 1) && (Dist[i] < min) &&(Dist[i] != 0 )){ k = i; min = Dist[i]; } } final[k] = 1;//k点离v点最近,将k 点保存在final中 /* 在v点到j点路径上,如果存在该点k ,使得v->k->j的距离小于v->j 的距离 */ for(j = 0;j < VN ; j++){ if((final[j] != 1) && (Dist[k] + G[k][j] < Dist[j] )){ Dist[j] = Dist[k] + G[k][j]; Path[j] = k;//存储该k点 } } } /* 打印出v点到其他顶点的最短路径及距离 */ for(i = 0 ;i < VN ; i++){ if(final[i]!=0){ k = i; while( k != v){ printf(" %d <- ",k); k = Path[k]; } printf(" %d ",v); printf(" \nshortPath is %d \n\n",Dist[i]); } else printf(" the Vertex %d no shortPah \n ",i); } } void main(){ int i ; for(i = 0 ;i < VN;i++){ GL[i] = NULL; } i =0; createGLink(G); printf("深度优先遍历\n "); DFS(GL,0); for(i = 0;i < VN ;i ++){ visit[i] = 0; } printf("\n\n\n广度优先遍历\n"); BFS(GL,0); printf(" \n\n\n最短路径算法\n"); Short(G,1); }
V1Þ V2ÞV3Þ V4ÞV5ÞV6ÞV7ÞV8
相关文章推荐
- 最短路径基本介绍(2)--Dijkstra算法(单源最短路径算法)
- Pku acm 2253 Frogger数据结构题目解题报告(六)—单源最短路径:Dijkstra算法
- [数据结构]Dijkstra算法求单源最短路径
- Dijkstra算法是解单源最短路径问题的一个贪心算法
- 杭电 1874 单源最短路径 Dijkstra算法
- Dijkstra算法实现单源最短路径
- 用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。
- Dijkstra算法|单源最短路径|贪心算法
- 单源最短路径问题(Dijkstra算法)第五集
- 图的邻接矩阵表示形式,DFS和BFS,最小生成树Prim和Kruscal,单源最短路径Dijkstra算法
- 单源最短路径----------Dijkstra算法
- 最小生成树Prim算法和单源最短路径Dijkstra算法
- Dijkstra算法求图的单源最短路径
- 算法与数据结构-单源最短路径之Dijkstra
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- 单源最短路径 dijkstra算法
- Dijkstra算法(单源最短路径)
- POJ1062 昂贵的聘礼 单源最短路径变形 dijkstra算法
- Dijkstra算法求图的单源最短路径
- Dijkstra算法|单源最短路径|贪心算法