上一篇主要讲了二叉树的先序,中序,后序遍历算法以及深度和节点的算法,这篇就讲一讲图的基本算法。
一、图的基本概念
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]];//找到当前顶点边表链表头指针
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算法求出单元最短路径
*/
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