C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)

上一篇主要讲了二叉树的先序,中序,后序遍历算法以及深度和节点的算法,这篇就讲一讲图的基本算法。

一、图的基本概念

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)。

《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》
《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》

二、图的存储结构(以无向图G1为例)

2.1邻接矩阵(关联矩阵、关系矩阵)

特点:由上述可知,无向图或网络的邻接矩阵是对称的。并且,该法比较简单,用一个二维数组就可存储。

缺点:浪费空间,可用处理“稀疏”矩阵的方式去处理。

   
《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》

2.2邻接表G1

邻接表是图的一种链式存储结构。在邻接表中,对图中的每个结点建立一个单链表。第i个单链表中的结点表示依附于顶点Vi的边(有向图中指以Vi为尾的弧).  在边少的情况下,用邻接表比邻接矩阵节省存储空间。

《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》

三、图的遍历

3.1深度优先遍历

从图的某一顶点V0出发,访问此顶点;然后依次从V0的未被访问的邻接点出发,深度优先遍历图,直至图中所有和V0相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。

《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》 上图遍历结果为:V1 –> V2 –> V4 –> V8 –> V5 –> V3 –> V6 –> V7

3.2广度优先遍历

从图的某一顶点V0出发,访问此顶点后,依次访问V0的各个未曾访问过的邻接点;然后分别从这些邻接点出发,广度优先遍历图,直至图中所有已被访问的顶点的邻接点都被访问到;若此时图中尚有顶点未被访问,则另选图中一个未被访问的顶点作起点,重复上述过程,直至图中所有顶点都被访问为止。

《C语言基本数据结构之三(图的广度及深度遍历,求单源最短路径的Dijkstra算法)》

上图遍历结果为: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]];//找到当前顶点边表链表头指针
		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


    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/to_perfect/article/details/53856487
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞