1,图论
定义:图(Graph)是一种非线性的数据结构,形式化描述为:
Graph= (V,R)
其中V={vi | vi属于datatype,i=0,1,2...,n-1}是图中的元素vi(称为顶点Vertex)的集合,
当n=0,V为空集
R={<vi,vj> | vi,vj属于V,且vi,vj之间存在路径,0<=i,j<=n-1}是顶点之间的关系集,
<vi,vj>为顶点vi,vj之间是否存在路径的判定条件。即若vi,vj之间存在路径,则关系<vi,vj>属于R。
有向图(Digraph): 弧
无向图(Undigraph): 边
网:若在图的关系<vi,vj>或<vj,vi>上附加一个值w,称w为弧或者边上的权。
带权的图称为网。(权w具体的含义在图不同领域中的应用而定,如顶点表示城市,权w可以为两个城市的距离等等)
顶点的度:顶点的边或弧的条数
路径:一点顶点到另一个顶点的方式
2,图的存储结构:
"数组表示法" "邻接表" "十字链表"
(1),数组表示法,又名邻接矩阵(adjacency matrix)
G =(V,R)
可以用两个数组来存储图:
一个一维数组存储G的顶点集V,
另外一个二维数组存储G中顶点间的关系集R,该二维数组就是所谓的邻接矩阵。
typedef char Vtype;//顶点的数据类型
typedef int Adjtype;//邻接矩阵的类型,其实就是边的权值类型
typedef struct
{
Vtype V[MAXN];//顶点的集合,一维数组
Adjtype Adj[MAXN][MAXN];//边的集合,二维数组表示,邻接矩阵
int vexnum;//图中顶点的个数
int arcnum;//图中边的条数
}mgraph;
(2)邻接表
所谓邻接表(Adjcency Lists)是将图中的每一个顶点V和由V发出的弧或者边构成一个单链表。
struct adj//邻结结点类型
{
int termIndex;//边的终点在顶点数组中的下标
int w;//权值
struct adj* next;
};
struct Vertex//起始顶点的类型
{
Vtype data;
struct adj*first;
};
struct Vertex graph[MAXN];//起始结点数组
3,图的遍历
图的遍历是树的遍历的一种推广,是按照某种规划(或次序)访问图中各顶点一次且仅一次的操作,
亦是将网状结构按照某种规则线性化的过程。
对图的遍历通常有"深度优先搜索"和"广度优先搜索"的方法。
(1)深度优先搜索算法(DFS:Depth First Search)
设初始化时,图中的各个顶点均未被访问,从图中某个顶点(设为v0)出发,访问v0,
然后搜索v0的一个邻接点vi,若vi未被访问,则访问之,再搜索vi的一个邻接点(深度优先),....
若某顶点的邻接点全部访问完毕,则回溯(Backtracking)到它的上一个顶点,然后再从此顶点又
按照深度优先的方法搜索下去,。。。直到所有的顶点都访问完毕。
(2)广度优先搜索算法(BFS:Breadth First Search)
类似树的层次遍历,初始时,图中各顶点均未被访问,从图中的某一个顶点(v0)出发,访问v0,
并依次访问v0的各个邻接点(广度优先),然后,分别从这些访问过的顶点出发,再按照广度优先的
搜索方式搜索其他的顶点,。。。直到能访问的顶点都访问完毕为止。
4,最短路径问题
解决带权的有向图中两顶点之间的最短路径问题有两个经典算法:
Dijkstra(迪杰斯特拉)算法和Floyd(弗洛伊德)算法
Dijkstra算法:是解决从网络中任一顶点(源点)出发,求它到其它各顶点(终点)的最短路径问题。
算法思路:按照路径的长度递增次序产生从某源点v到图中其余各顶点的最短路径。
Dijkstra算法需要用到两个辅助向量:
(1)向量 s[n]
s[i] == 1,表示从源点v到该点vi的最短路径已经求出来了
s[i] == 0,表示从源点v到该点vi的最短路径还没有求出来
初始化时,s[v]=1,其他s[i]=0(0<= i <=n-1,i不等于v)
(2)向量 dist[n]
dist[n]存放从源点v到vi这个点的(当前的)最短路径长度
初始化时
当v可以直接到vi,dist[i] =<v,vi>的权w
当v不可以直接到vi,dist[i] = 无穷大
算法步骤:
step1 :显然,从源点v到其它个顶点的第一条最短路径长度dist[u],
dist[u] = min{dist[w] | w=0,1,2,...n-1,且s[w]=0}
表示在所有未求出的当前最短路径中找出一条最短的,其长度作为 当前求出的最短路径长度。
step2:
对s[w]=0的w,如果dist[u]+<u,w> < dist[w]
==>dist[w] = dist[u] + <u,w>
然后重复step1,step2直到所有的s[n]都等于1为止。
图的代码及分析
#include <stdio.h>
#include <stdlib.h>
/*************************************************************************************
'\n'与'\t','空格'的区别:
用'\n'可以刷出缓存区里面的东西,用别的只能等主函数结束才能显示缓存区里的东西;
例如: 程序中间某部分出现死循环时,其之前存的东西在缓存区内,
只有在遇到 '\n' 才会显示,否则不会显示;
所以'\n'可以用来判断之前的代码哪里错误!!!!!
用printf("aaa\n");查找死循环位置时也必须以'\n'刷出'aaa'!!!!!
**********************************************************
为什么要用getchar();吸收??
用gets();吸收会出错!!!!!!
用gets()输入时键盘上是以回车符('\n')结束输入的,
最终会自动在最后添加一个'\0'符,'\n'符也依然存在,
但是下次会被第一个输入数据覆盖,所以没有存在的意义!!
用scanf()输入时键盘上是以回车符('\n')结束输入的,
最终'\n'符依然存在,
连续使用scanf()输入时会将这个'\n'赋作为你输入的第一个字符,以空格形式存在。
(虽然你这次并没有在第一个字符处输入'\n'!!!!!!)
***********************************************/
#define MAXN 1024 //建造大数组:容量为1024
#define W_MAX 65535 //表示顶点间的关系:距离为65535(无穷大)
typedef char Vtype;//顶点的数据类型
typedef int Adjtype;//邻接矩阵的类型,其实就是边的权值类型
/***********************************
图包含的数据为:
1.顶点(有许多顶点,但是不知道具体多少个
所以用一个很大的数组来表示;
!!!!该一维数组里面放顶点!!!!!!
2.边的集合(所有顶点连成一条线,用两条相同的垂直的线构成一个面)
即构造一个二维数组,数组行跟列都是你所有顶点构成的那条线
长度和内容都相同;
!!!!该二维数组里面放行顶点到列顶点的权!!!!!
3.图中顶点的个数(用来决定面的面积)
!!!!决定两个数组能取到的最大下标的值!!!!!!!!
4.图中边的条数(一点顶点直接到另一个顶点的一种方式称为一条边)的总和
什么是边??
一点顶点直接到另一个顶点的(一种方式)称为(一条边)
**********************************/
typedef struct
{
Vtype V[MAXN];//顶点的集合,一维数组
Adjtype Adj[MAXN][MAXN];//边的集合,二维数组表示,邻接矩阵
int vexnum;//图中顶点的个数
int arcnum;//图中边的条数
}mgraph;
/* 返回元素字符x 顶点数组V中的下标,
n为顶点数组V数组的个数
如果没有找到则返回-1
*/
/***************************************
定义一个函数专门用来寻找字符X在数组中的位置,
若X存在,返回X在数组中的下标,否则返回-1;
需要传入的参数:
1.数组
2.数组的最大下标(数组容量)
3.需要查找的字符X
使用函数是为了实现功能模块化,易于查错和多次使用
***************************************/
int find_index(Vtype *V,int n,char x) //寻找并返回字符X在数组中的位置
{
int i=0;
for(i=0;i<n;i++)
{
if(V[i] == x)
// if(g->V[i] == 'x') //错误!!!!!!
//这样写是判断g->V[i]是否等于字符x的ASCII码值
{
return i;
}
}
return -1;
}
/*创建图*/
/**************************************************
1.创建一个空的图(初始化):
顶点个数和边的条数都为0;
顶点和顶点之间的关系后面再建立;
2.给图赋顶点:
赋值进去一个vexnum加一;
3.给图的顶点之间赋权(先找位置,再填充二维数组;):
先定义两个字符代表两个顶点,把这两个顶点放到查找函数中找到他们的位置
第一个顶点的返回值作为二维数组的行,
第二个顶点的返回值作为二维数组的列,
再定义一个数字作为这两个顶点之间的权(关系),
最后判断这两个顶点是否存在?
若存在,就将权装进二维数组中对应的位置
********************************************/
mgraph * create_graph()
{ //1.创建一个空的图(初始化):
mgraph *g = malloc(sizeof(*g));
g->vexnum = 0;
g->arcnum = 0;
printf("please input the vertex string:\n");
char str[MAXN];
gets(str); //一次性给所以顶点赋值(得到一个字符串)
/*step1:给顶点数组赋值*/
int i=0,j;
while(str[i] != '\0') //将字符串逐个装进顶点集合这个数组中
{
g->V[i] = str[i];
i++;
}
g->vexnum = i; //统计出顶点个数
/*
step2:给邻接矩阵赋值
*/
for(i=0;i<g->vexnum;i++) //将边的集合初始化(二维数组所以元素全部置65535)
{
for(j=0;j<g->vexnum;j++)
{
g->Adj[i][j] = W_MAX;
}
}
//此时已经得到了已被赋值的顶点数组(一维数组)和未被赋值的边的集合(二维数组)
printf("please input the arc\n");
while(1)
{
Vtype s,p; //定义两个字符,用来存放自己要建立关系的两个顶点
Adjtype w; //定义一个数字,用来存放两个顶点之间的权(关系)
scanf("%c%c%d",&s,&p,&w);
getchar();//吸收'\n'
if(s == '#') //若我输入的是‘#’,跳出循环,停止建立顶点之间的关系
{
break;
}
int si,pi;
si = find_index(g->V,g->vexnum,s); //寻找并返回顶点s在数组中的位置
pi = find_index(g->V,g->vexnum,p); //寻找并返回顶点p在数组中的位置
if(si!=-1 && pi!= -1)
{ //如果顶点数组中s和p这两个顶点都找到了!!!
g->Adj[si][pi] = w;
//将两个顶点之间的权放进边的集合(表示出这两个顶点之间的权)!!
g->arcnum++; //边的条数加 1
}
}
return g; //返回建立好的整个图
}
/***************************************************
把整个图打印出来
即打印出顶点数组
*****************************************/
void print_graph(mgraph *g)
{
putchar('\t');
int i=0,j;
for(i=0;i<g->vexnum;i++) //i小于顶点个数
{
printf("%c\t",g->V[i]); //打印表格的行(横)
}
putchar('\n');
for(i=0;i<g->vexnum;i++)
{
printf("%c\t",g->V[i]); //打印表格的列(纵)
for(j=0;j<g->vexnum;j++)
{
if(g->Adj[i][j] == W_MAX) //若没有赋权
{
printf("#\t"); //打印#
}
else
{
printf("%d\t",g->Adj[i][j]); //否则就把权打印出来
}
}
putchar('\n');
}
}
/*==========深度优先搜索算法=========*/
int visited[MAXN];//访问标识数组,表示相应的顶点是否已经被访问过
//为1表示已经被访问过了,0表示没有被访问
/*********************************************************
定义一个全局变量(数组)作为顶点是否打印过的标志
先统一赋初值, 在DFSTraverse(mgraph *g中把他全部置0了)
若没打印过里面存的就是初值,
若打印过,就把初值改了
要学会使用全局变量!!!!!!!!!!!!!!!!!
***************************************/
/*找到图g中第v个顶点的第一个邻接点的下标*/
int FirstAdjVex(mgraph *g,int v) //找到图g中第v个顶点的第一个邻接点的下标
{ //传入图和数字V(v作为数组的下标)
int i;
for(i=0;i<g->vexnum;i++)
{
if(g->Adj[v][i] != W_MAX) //若这个位置存在权
{
return i; //将这个权的行下标 i 返回给主调函数
}
}
return -1; //不存在就返回 -1
}
/************************************************************
从图g中找出第v个顶点的下标为w的邻接点的后面那个邻接点的下标
第w个邻接点在上一轮已经被访问过了,所以从w+1开始查找!!!!!
**********************************************/
int NextAdjVex(mgraph *g,int v,int w)
{//传入图和数字V(v作为数组的下标)和数字w(w+1作为本次循环查找的起始位置)
int i;
for(i=w+1;i<g->vexnum;i++) //w+1作为本次循环查找的起始位置,
{ //因为w在上次已经被提取出来了,所以这次从w+1开始查找!!!!!
if(g->Adj[v][i] != W_MAX)
{
return i;
}
}
return -1;
}
/*从图g中的第v个顶点出发,按照深度优先搜索的方法去【访问】,输出的是顶点*/
/****************************************************************
函数 void DFS(mgraph *g,int v) 传入整个(图g)和一个顶点在顶点数组(一维数组)中的(下标V),
1.把顶点v的标志位置1;
2.打印该顶点;
3.得到该顶点的第一个邻接顶点在顶点数组(一维数组)中的(下标w),
4.判断第w个顶点有没有被访问过:
(1).被访问过,其标志位为 0 (visited[w] == 0)
将整个(图g)和该顶点的第一个邻接顶点在顶点数组(一维数组)中的(下标w)
传入函数 void DFS(mgraph *g,int w) 中(传给他本身,从头到尾再执行一次,
如果满足条件就再传给他本身,从头到尾再执行一次,如此循环直到某次条件不满足开始逐层跳出,
(最内层完整执行完后向外一层执行【递归形式那行代码】之后的代码,直到外层函数执行完才开始执行他外面那层的);
(2).否则循环结束!!
注意:递归调用他本身时进入函数时是由外层到内存递归,
执行完了跳出函数时是由最内层一层层向外执行再跳出的。
若把一个函数表示成一个房间,那递归就是在最开始的房间里再建造N个房间,N为递归次数(函数层数),
你要从这个房子的前门进入后门出去,就必须先走进N个前门,进入最内存的房间,再走出N个后面才可以!!!
!!!!!!!容易让人误认为进入最内层房间后直接跳出所有房间,
其实出了小房间,小房间外层的大房间里没走完的路依然要一步步走完!!!!!!!!
**********************************/
void DFS(mgraph *g,int v)
{
visited[v] = 1; //将visited[v]置 1 (访问并打印了顶点V[v])
//visited[]为存储标志位的数组
printf("%c ",g->V[v]); //打印出顶点V[v];
/*得到v的第一个邻接点的下标w,
如果它没有被访问,就按照DFS的方法去访问它*/
int w;
for(w=FirstAdjVex(g,v);w>=0;w=NextAdjVex(g,v,w))
//找到图g中第v个顶点的第一个邻接点的下标赋值给w(作为for循环的起始位置)
//找出第v个顶点的下标为w的邻接点的后面那个邻接点的下标(作为循环的移动条件)
{
if(visited[w] == 0) //若第w个没有被访问过
{ //w是v的第一个邻结点
DFS(g,w); //调用他本身去访问w
}
}
}
/*按深度优先搜索的方式【遍历】图g中的每个顶点*/
/***************************************************************
这里用到了标志位思想;用来避免重复访问
*****************************/
void DFSTraverse(mgraph *g)
{
printf("DFS: ");
int i;
for(i=0;i<g->vexnum;i++)//把访问标识数组清零
{ //这是个全局变量,用了全局变量不用再把数组名传给被调函数了,不容易出错
visited[i] = 0;
} //先全部至0,表示一个都没有访问过,有这个标识在就能【避免重复访问】!!!!!!
for(i=0;i<g->vexnum;i++)//从图g的第i个顶点出发用DFS方式去遍历图
{
if(visited[i] == 0)
{
DFS(g,i); //首次调用递归函数,给出第一个顶点的下标
}
}
printf("\n");
}
/*=============广度优先搜索=============*/
/***********************************************************************************
typedef int ElemType;
struct node
{
ElemType data;
struct node* next;
struct node* prev;
};
struct linkQueue
{
struct node* front;
struct node* rear;
int length;
int max;
};
struct linkQueue* creatQueue(int max)
{
struct linkQueue*q=(struct linkQueue*)malloc(sizeof(struct linkQueue));
q->front=NULL;
q->rear=NULL;
q->length=0;
q->max=max;
return q;
}
int isEmpty(struct linkQueue * q)
{
if(q->length==0)//q->rear==NULL ||q->front==NULL
{
return 1;
}
return 0;
}
void enQueue(struct linkQueue * q, ElemType data)
{
//1.创建结点
struct node*pNew=(struct node*)malloc(sizeof(*pNew));
pNew->data=data;
pNew->next=NULL;
pNew->prev=NULL;
//2.入队
q->length++;
if(q->front==NULL)
{
q->front=q->rear=pNew;
}
else
{
q->rear->next=pNew;
pNew->prev=q->rear;
q->rear=pNew;
}
}
ElemType deQueue(struct linkQueue * q)
{
if(isEmpty( q))
{
return 0;
}
//2.删除结点
int data=q->front->data;
struct node*h=q->front;
q->length--;
if(q->front==q->rear)
{
free(h);
q->front=NULL;
q->rear=NULL;
}
else
{
q->front=q->front->next;
q->front->prev=NULL;
h->next=NULL;
free(h);
}
return data;
}
//广度优先搜索:BFS
void BFSTraverse(mgraph *g)
{
printf("BFS: ");
int i;
for(i=0;i<g->vexnum;i++)//访问标识数组置0
{
visited[i] = 0;
}
struct linkQueue* lq = creatQueue(g->vexnum);//初始化一个队列
for(i=0;i<g->vexnum;i++)
{
if(visited[i] == 0)
{
visited[i] = 1;
printf("%c ",g->V[i]);//访问
enQueue(lq, i);//把访问过的顶点如队列
while( !isEmpty(lq))
{
int j = deQueue(lq);//出队
int w;
for(w=FirstAdjVex(g,j);w>=0;w=NextAdjVex(g,j, w))
{
if(visited[w] == 0)
{
visited[w] = 1;
printf("%c ",g->V[w]);
enQueue(lq, w);
}
}
}
}
}
putchar('\n');
}
*********************************************/
/*用Dijkstra算法求出从v点到其它各定点的最短路径长度*/
int s[MAXN];//是否求出最短路径的标志数组
//标志是否求出最短路径,是就置 1,否则置 0
int dist[MAXN];//存放当前到各点的最短路径长度
//当出现比他小的时,数组中的元素随时更新
void Dijkstra(mgraph *g,int v)
{//v为我设置的源顶点
/*初始时,把s[n],dist[n]初始化*/
int i;
for(i=0;i<g->vexnum;i++)
{
s[i] = 0; //将所有标志位全部初始化(置 0)
dist[i]= g->Adj[v][i]; //读入下标为v的顶点到各顶点之间的权的初始值
}
dist[v] = 0; //将他本身值0,(他到自己的权)
s[v] = 1; //将他本身的标志位置 1
int min;//源点到当前最优顶点的路径长度
int min_i;//当前最优顶点的下标
int times;//寻找最短路径的次数,每次找到一条
for(times=0;times<g->vexnum-1;times++)
{ //最多能找到顶点数减 1 条路径
/*step1:找到当前最优顶点,同时找到一条最短路径*/
for(i=0;i<g->vexnum;i++)//保证min为没有求出最短路径中的dist数组里的某一个值
{
if(s[i] == 0) //若没有找到最佳路径
{
min = dist[i]; //将当前v点到下标为i的这个点的长度赋给min
break;
}
}
for(i=0;i<g->vexnum;i++)
{ //从第一个点开始寻找最短路径直到最后一个点
// if(S[i]==0&&min<=dist[i]) 错误!!有比他短的才更新
if(s[i] == 0 && dist[i] <= min)
{//若i点还没找到最短路径且当前路径比之前的路径短
min = dist[i]; //更新最短路径的长度
min_i = i;//更新最短路径的下标
}
}
s[min_i] =1;//当与所以路径都比较完之后,将标志位置 1
/*step2 :更新dist数组*/
for(i=0;i<g->vexnum;i++)
{
if(s[i]==0)
{ //将还没找到最短路径的顶点
if(dist[min_i]+g->Adj[min_i][i] < dist[i])
{
dist[i] = dist[min_i] + g->Adj[min_i][i];
}
}
}
}
}
/*************************************************************
这个函数只执行了一次,
输入的是整个图和图中的一个顶点,
执行的操作是填充用来存放【顶点v到各个顶点的最短距离】(权的最小值);
这个函数虽然没有返回值,也没有改变过传进去的东西,
但是给一个全局变量赋值了!!
在后面的主函数中可以直接使用这个填充过的数组!!!
*****************************************************************/
/************************************************************************
初始化后:dest[g->Vnum]={0,15,2,12,W_MAX,W_MAX,W_MAX}; //源点下标为 0
times=0: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
0排除
得到min=2(离源点最近的点的距离为2),min_i=2(这个点的下标为2)//标记S[2]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为2的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[2]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[4]=2+8=10<W_MAX;更新
dest[5]=2+4=6<W_MAX;更新
dest[6]=2+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,12,10,6,W_MAX};
times=1: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,12,10,6,W_MAX};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
2排除
得到min=6(离源点最近的点的距离为6),min_i=5(这个点的下标为5) //标记s[5]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为5的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[5]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[3]=6+5=11<12;更新
dest[6]=6+10=16<W_MAX;更新
dest[g->Vnum]={0,15,2,11,10,6,16};
times=2: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,16};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
6排除
得到min=10(离源点最近的点的距离为10),min_i=4(这个点的下标为4) //标记s[5]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为4的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[4]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[2]=10+W_MAX>W_MAX;不更新
dest[6]=10+9=19>16;不更新
dest[g->Vnum]={0,15,2,11,10,6,16};
times=3: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,16};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
10排除
得到min=11(离源点最近的点的距离为11),min_i=4(这个点的下标为3) //标记s[3]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为4的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[3]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[6]=11+3=14<16;更新
dest[g->Vnum]={0,15,2,11,10,6,14};
times=4: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,14};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
11排除
得到min=14(离源点最近的点的距离为14),min_i=6(这个点的下标为6) //标记s[6]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为6的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[6]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[2]=14+4=18>15;不更新
dest[5]=14+W_MAX>W_MAX;不更新
dest[4]=14+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,11,10,6,14};
times=5: for(i=0;i<g->Vnum;i++) 得到min=15,
for(i=0;i<g->Vnum;i++)
if(S[i]==0&&dest[i]<=min)
此时最短路径数组已更新,dest[g->Vnum]={0,15,2,11,10,6,14};
【新更新进来的数据也要用来进行比较】!!!!!!!!!!!!!!!
14排除
得到min=15(离源点最近的点的距离为14),min_i=1(这个点的下标为1) //标记s[1]=1
for(i=0;i<g->Vnum;i++)
if(s[i]==0)
if(dest[min_i]+g->Adj[min_i][i]<dest[i])
将源点与离下标为6的顶点最近的顶点的距离计算出来(路线为 源点---> g->V[1]--->g->V[i];
若这个距离比他原本的距离小,更新原本的距离为这个距离
dest[4]=15+6>10;不更新
dest[6]=15+W_MAX>W_MAX;不更新
dest[g->Vnum]={0,15,2,11,10,6,14};
最终数组为:dest[g->Vnum]={0,15,2,11,10,6,14};
*************************************************************************/
int main()
{
mgraph *g = create_graph(); //得到一个图(顶点,顶点之间的权,顶点个数,边的条数等所有信息都有)
print_graph(g); //打印这个图
DFSTraverse(g);//深度优先遍历这个图
BFSTraverse(g);//广度优先遍历这个图
int v = 0;
Dijkstra(g,v);//求这个图的所有顶点到顶点V的最短路径(最小的权)
int i;
for(i=0;i<g->vexnum;i++)
{
printf("%c->%c path is %d\n",g->V[v],g->V[i],dist[i]); //打印所有顶点到顶点V的最短路径(最小的权)
}
return 0;
}
/************************************************************
若没有用getchar()在scanf("%c%c%d",&p,&s,&i);后面
吸收'\n'会导致如下结果,
abcdef
ab5
bc15
cd20
de25
#c5
#d6
a b c d e f
a # # # # # #
b # # 15 # # #
c # # # # # #
d # # # # # #
e # # # # # #
f # # # # # #
**************************/
/*********************************************
最终运行结果:
abcdefg
ab15
ac2
ad12
be6
ce8
cf4
dg3
eg9
fd5
fg10
gb4
#d5
a b c d e f g
a # 15 2 12 # # #
b # # # # 6 # #
c # # # # 8 4 #
d # # # # # # 3
e # # # # # # 9
f # # # 5 # # 10
g # 4 # # # # #
___________________________________________
a
b
e
g
c
f
d
0 15 2 11 10 6 14
**************************************************/