本文具体代码都在第一个的代码上面进行的相应修改而成
1.图的基本概念
定义:图(Gragh)是一种非线性化的数据的结构
Gragh = (V,R)
其中V = {Vi|Vi属于datatype }是图中元素Vi(顶点 Vertex )
的集合 当n = 0; V是空集
R = {<Vi,Vj>|<Vi,Vj>属于V 且p(Vi,Vj)存在}}是图中顶点之间的关系集
P(Vi,VJ)表示顶点Vi和Vj之间是否存在一条路径 也就是P(Vi,Vj)存在,
那么关系P(Vi,VJ)属于R
分类:
有向图与无向图
有向图的顶点之间的路径有方向 顶点之间的连线称为弧
无向图的顶点之间的路径没有方向 双向导通 其连线称为 边
权 w
若在图的关系上<Vi,Vj>附加一个值w 这个值称为权值
表示的是一个“成本” 在不同领域的,所代表的含义也不同
比如地图上表示两个城市之间的距离
网 带权的图
路径 两个顶点之间,怎么走
2.图的存储结构
“数组表示法” 邻接矩阵
“邻接表”
“十字链表”
“邻接多重表”
1.数组表示法 顺序结构
G = (V,R)
其中V 是顶点的集合 1 2 3 4 5 6 7 8 9
用一个一维数组去保存
R为关系的集合
A B C D 顶点集合
A 255 255 3 2
B 1 255 255 5
C 3 255 255 6
D 255 4 7 255
关系用一个二维数组去保存
如果这个图有权值,数据关系填权值
两个顶点之间没有直接的关系 则填无穷大
对于没有权值的图 一般选择0/1表示两个顶点之间
能够直接到达 无穷大表示不能够直接到达
typedef int vType; //顶点元素的类型
typedef int adjType;//权值类型#define NUM_MAX 100 //图中顶点的个数
typedef struct MyGragh //顶点的数据类型
{
//数据域
vType Vertex[NUM_MAX];
//关系域
adjType Relation[NUM_MAX][NUM_MAX];//图中有效顶点的个数
int vexNum;
/*
看你需要什么参数
*/
}MyGragh;
可读性 函数 变量 类型的命名
可复用性 代码可以简单修改或者不修改后用于另一个项目
数组表示法具体代码:
/*
Graph.c
Graph.h
main.c
三个文件
*/
//-------------
// Graph.h
#ifndef __GRAPH_H__
#define __GRAPH_H__
#define VMAX 100
typedef char VElemtype;//顶点元素的类型
typedef int adjType; //边上权的类型
typedef struct MyGragh
{
VElemtype Vertex[VMAX];//顶点集合V
adjType A[VMAX][VMAX];//临界矩阵 "边"
int VexNum;//图中有效的顶点数;
}MyGragh;
MyGragh *CreateGraph();
//依次按照深度优先的规则访问图G
void DFSTravers(MyGragh *G);
void BFSTravers(MyGragh *G);
void myVisit(MyGragh *G,int v0);
void Dijkstra(MyGragh *G,int v0);
#endif
//---------------------
//---------------------
//Graph.c
#include <stdio.h>
#include <stdlib.h>
#include "Graph.h"
#define INT_MAX 65535
#define TRUE 1
#define FALSE 0
void myVisit(MyGragh *G,int v0)
{
if(sizeof(VElemtype) == sizeof(int))
{
printf("%d ",G->Vertex[v0]);
}
else if(sizeof(VElemtype) == sizeof(char))
{
printf("%c ",G->Vertex[v0]);
}
}
static int GetVexIndex(MyGragh *G,VElemtype v0)
{
for(int i = 0;i < G->VexNum;i++)
{
if(G->Vertex[i] == v0)
{
return i;
}
}
return -1;
}
MyGragh *CreateGraph()
{
//先输入顶点集合 再输入关系集
int i,j;
VElemtype data;
MyGragh *G = (MyGragh*)malloc(sizeof(MyGragh));
G->VexNum = 0;
for(i = 0;i < VMAX;i++)
{
G->Vertex[i] = 0;
}
for(i = 0;i < VMAX;i++)
{
for(j = 0;j < VMAX;j++)
{
G->A[i][j] = INT_MAX;
}
}
//1.顶点集合
printf("请输入顶点集合 以#号键结束\n");
for(i = 0;1;i++)
{
scanf("%c",&data);
if(data == '#' && G->VexNum < VMAX )//假设输入-1结束输入
{
break;
}
G->Vertex[i] = data;
G->VexNum ++;
}
//打印出来 检查一下
for(int i = 0;i < G->VexNum;i++)
{
printf("%c ",G->Vertex[i]);
}
printf("\n");
// 2.关系集合
// 输入边的关系 起点 终点 起点到终点的权值
// 假设起点 输入 -1 结束
printf("请输入关系集合: 起点 终点 起点到终点的权值\n");
VElemtype startData,endData;
int w;
int StratIndex,endIndex;
while(1)
{
getchar();//把回车读出来
scanf("%c %c %d",&startData,&endData,&w);
if(startData == '#')
{
break;
}
StratIndex = GetVexIndex(G,startData);
endIndex = GetVexIndex(G,endData);
if(StratIndex == -1 || endIndex == -1)
{
printf("你输入的起点或终点有错 请重新输入\n");
continue;
}
G->A[StratIndex][endIndex] = w;
}
for(i = 0;i < G->VexNum;i++)
{
for(j = 0;j < G->VexNum;j++)
{
printf("%d\t",G->A[i][j]);
}
printf("\n");
}
return G;
}
//--------------------
//--------------------
//main.c
#include <stdio.h>
#include "Graph.h"
int main()
{
MyGragh *G = CreateGraph();
return 0;
}
//---------
2.邻接表 链式结构
所谓的邻接表(adjacency Lists),是将图中每一个顶点V和由V出发的
边或弧构成的单链表
数据类型
typedef int vType;//顶点元素的类型
typedef int adjType;//边的权值w类型
//图中顶点的最大个数
#define NUM_MAX 100//关系的类型
typedef struct MySide
{
//终点下标
int term;
//权值
adjType w;
//下一个关系的指针
struct MySide* next;}MySide;
//顶点的类型
typedef struct
{
//数据域
vType data;
//关系域
MySide *first;
}Vertex;Vertex MyGragh[NUM_MAX]
3.图的遍历
图的遍历是树的遍历的推广 是按照规则有且仅有一次的去访问图中每个顶点
这是将网状结构按照某种规则线性化的过程
对图的遍历通常由广度优先搜索和深度优先搜索方法,二者是人工智能基础
1.深度优先搜索(DFS:Depth First Search)
设初始时,图中各顶点均未被范文,以图中顶点V0出发
访问V0 然后搜索V0的邻接点Vi如果Vi未被访问,则访问Vi
再以同样的规则(DFS)去遍历Vi。直到所有邻接点都被访问过,
则回溯到它的上一个顶点
直到所有顶点都被访问过了
首先我需要一个标志 告诉我那些顶点被访问过了
char visited[NUM_MAX] = {0};//0表示未被访问 1表示被访问了DFS(G,vi)
{
//1.递归先考虑终止条件 所有的邻接点都被访问了
我们有两种方式 一种是满足了终止条件 结束函数
一种是满足了条件才执行
if(如果vi的第一个邻接点未被访问 才进行访问改节点)
{
myVisit(Vi的第一个邻接点);
标记这个顶点被访问
visited[Vi的第一个邻接点] = 1;
DFS(G,Vi的第一个邻接点)
}vi的第二个邻接点以同样的方式
第三个...
第四个...
=》所以代码可以写成 循环的方式
for(v = Vi的第一个邻接点;v存在;v 等于 vi的下一个邻接点)
{
if(v未被访问)
{
myVisit(v);
标记v被访问;DFS(G,v的第一个邻接点)
}
}
}//按照深度优先的规则访问图G
DFSTravest(G)
{
for(int i = 0;i < G->vexNum;i++)
{
if(这个顶点未被访问)
{
深度优先搜索的方式访问这个顶点
DFS(G,V0);
}
}
}
DFS具体代码:
/*
Gragh.c
Gragh.h
main.c
三个文件
*/
//----------
//Graph.h
#ifndef __GRAGH_H__
#define __GRAGH_H__
#define VMAX 100
typedef char VElemtype;//顶点元素的类型
typedef int adjType; //边上权的类型
typedef struct MyGragh
{
VElemtype Vertex[VMAX];//顶点集合V
adjType A[VMAX][VMAX];//临界矩阵 "边"
int VexNum;//图中有效的顶点数;
}MyGragh;
MyGragh *CreateGraph();
//依次按照深度优先的规则访问图G
void DFSTravers(MyGragh *G);
void BFSTravers(MyGragh *G);
void myVisit(MyGragh *G,int v0);
void Dijkstra(MyGragh *G,int v0);
#endif
//-------------------
//-------------------
//Gragh.c
#include <stdio.h>
#include <stdlib.h>
#include "Gragh.h"
#define INT_MAX 65535
#define TRUE 1
#define FALSE 0
void myVisit(MyGragh *G,int v0)
{
if(sizeof(VElemtype) == sizeof(int))
{
printf("%d ",G->Vertex[v0]);
}
else if(sizeof(VElemtype) == sizeof(char))
{
printf("%c ",G->Vertex[v0]);
}
}
static int GetVexIndex(MyGragh *G,VElemtype v0)
{
for(int i = 0;i < G->VexNum;i++)
{
if(G->Vertex[i] == v0)
{
return i;
}
}
return -1;
}
MyGragh *CreateGraph()
{
//先输入顶点集合 再输入关系集
int i,j;
VElemtype data;
MyGragh *G = (MyGragh*)malloc(sizeof(MyGragh));
G->VexNum = 0;
for(i = 0;i < VMAX;i++)
{
G->Vertex[i] = 0;
}
for(i = 0;i < VMAX;i++)
{
for(j = 0;j < VMAX;j++)
{
G->A[i][j] = INT_MAX;
}
}
//1.顶点集合
printf("请输入顶点集合 以#号键结束\n");
for(i = 0;1;i++)
{
scanf("%c",&data);
if(data == '#' && G->VexNum < VMAX )//假设输入-1结束输入
{
break;
}
G->Vertex[i] = data;
G->VexNum ++;
}
//打印出来 检查一下
for(int i = 0;i < G->VexNum;i++)
{
printf("%c ",G->Vertex[i]);
}
printf("\n");
// 2.关系集合
// 输入边的关系 起点 终点 起点到终点的权值
// 假设起点 输入 -1 结束
printf("请输入关系集合: 起点 终点 起点到终点的权值\n");
VElemtype startData,endData;
int w;
int StratIndex,endIndex;
while(1)
{
getchar();//把回车读出来
//从键盘读取一个关系
scanf("%c %c %d",&startData,&endData,&w);
if(startData == '#')
{
break;
}
//获取起点终点下标
StratIndex = GetVexIndex(G,startData);
endIndex = GetVexIndex(G,endData);
if(StratIndex == -1 || endIndex == -1)
{
printf("你输入的起点或终点有错 请重新输入\n");
continue;
}
//对相应位置的进行赋值 这里采用行表示起点 列表示终点
G->A[StratIndex][endIndex] = w;
}
for(i = 0;i < G->VexNum;i++)
{
for(j = 0;j < G->VexNum;j++)
{
printf("%d\t",G->A[i][j]);
}
printf("\n");
}
return G;
}
char visited[VMAX] = {FALSE};//0表示未被访问 1表示被访问了
/*
func:获取下一个邻接点
G你从那个图的顶点集合搜索 vi你搜索谁的邻接点 V你这一次从第几列开始搜索
*/
int GetNextApp(MyGragh *G,int vi,int v)
{
for(int i = v;i < G->VexNum;i++)
{
//如果vi到i顶点对应的权值不为无穷大 意味着这是它的邻接点
if(G->A[vi][i] != INT_MAX)
{
return i;
}
}
return -1;
}
void DFS(MyGragh *G,int vi)
{
int v = 0;
if(visited[vi] == FALSE)
{
myVisit(G,vi);
visited[vi] = TRUE;
for(v = GetNextApp(G,vi,v);v != -1;v = GetNextApp(G,vi,v+1))
{
if(visited[v] == FALSE)
{
myVisit(G,v);
visited[v] = TRUE;
DFS(G,v);
}
}
}
}
//按照深度优先的规则访问图G
void DFSTravers(MyGragh *G)
{
for(int i = 0;i < G->VexNum;i++)
{
if(visited[i] == FALSE)
{
//深度优先搜索的方式访问这个顶点
DFS(G,i);
}
}
printf("\n");
}
//---------------------
//---------------------
//main.c
#include <stdio.h>
#include "Gragh.h"
int main()
{
MyGragh *G = CreateGraph();
DFSTravers(G);
//printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
return 0;
}
//---------------
2.广度优先搜索(BFS; breadth First Search)
类似与树的层级遍历,先访问节点本身,然后再访问节点周围的邻接点,
访问完所有的邻接点后,再按照同样的规则访问邻接点的邻接点
这种必然会用到队列
char visited[NUM_MAX] = {0};//0表示未被访问 1表示被访问了
BFSTravese(G)
{
//重置visited
for(int i = 0;i <NUM_MAX;i++)
{
visited[i] = FALSE;
}
初始化一个队列
for(int v0 = 0;v0 < G->vexNum;v0++)
{
if(这个顶点v0未被访问)
{
1.访问V0
标记v0被访问;
2.v0入队
while(队列非空)
{
出队
//依次访问出队顶点的所有邻接点,并入队
for(v = Vi的第一个邻接点;v存在;v 等于 vi的下一个邻接点)
{
if(v未被访问)
{
myVisit(v);
标记v被访问;
入队
}
}
}
}
}
}
BFS具体代码:
/*
Gragh.h
Gragh.c
LinkedQueue.h
LinkedQueue.c
main.c
五个文件
*/
//--------------
//Gragh.h
#ifndef __GRAGH_H__
#define __GRAGH_H__
#define VMAX 100
typedef int VElemtype;//顶点元素的类型
typedef int adjType; //边上权的类型
typedef struct MyGragh
{
VElemtype Vertex[VMAX];//顶点集合V
adjType A[VMAX][VMAX];//临界矩阵 "边"
int VexNum;//图中有效的顶点数;
}MyGragh;
MyGragh *CreateGraph();
//依次按照深度优先的规则访问图G
void DFSTravers(MyGragh *G);
void BFSTravers(MyGragh *G);
void myVisit(MyGragh *G,int v0);
void Dijkstra(MyGragh *G,int v0);
#endif
//-------------------
//-------------------
//Gragh.c
#include <stdio.h>
#include <stdlib.h>
#include "LinkedQueue.h"
#include "Gragh.h"
#define INT_MAX 65535
#define TRUE 1
#define FALSE 0
void myVisit(MyGragh *G,int v0)
{
if(sizeof(VElemtype) == sizeof(int))
{
printf("%d ",G->Vertex[v0]);
}
else if(sizeof(VElemtype) == sizeof(char))
{
printf("%c ",G->Vertex[v0]);
}
}
static int GetVexIndex(MyGragh *G,VElemtype v0)
{
for(int i = 0;i < G->VexNum;i++)
{
if(G->Vertex[i] == v0)
{
return i;
}
}
return -1;
}
MyGragh *CreateGraph()
{
//先输入顶点集合 再输入关系集
int i,j;
VElemtype data;
MyGragh *G = (MyGragh*)malloc(sizeof(MyGragh));
G->VexNum = 0;
for(i = 0;i < VMAX;i++)
{
G->Vertex[i] = 0;
}
for(i = 0;i < VMAX;i++)
{
for(j = 0;j < VMAX;j++)
{
G->A[i][j] = INT_MAX;
}
}
//1.顶点集合
printf("请输入顶点集合 以#号键结束\n");
for(i = 0;1;i++)
{
scanf("%d",&data);
if(data == -1 && G->VexNum < VMAX )//假设输入-1结束输入
{
break;
}
G->Vertex[i] = data;
G->VexNum ++;
}
//打印出来 检查一下
for(int i = 0;i < G->VexNum;i++)
{
printf("%d ",G->Vertex[i]);
}
printf("\n");
// 2.关系集合
// 输入边的关系 起点 终点 起点到终点的权值
// 假设起点 输入 -1 结束
printf("请输入关系集合: 起点 终点 起点到终点的权值\n");
VElemtype startData,endData;
int w;
int StratIndex,endIndex;
while(1)
{
getchar();//把回车读出来
//从键盘读取一个关系
scanf("%d %d %d",&startData,&endData,&w);
if(startData == -1)
{
break;
}
//获取起点终点下标
StratIndex = GetVexIndex(G,startData);
endIndex = GetVexIndex(G,endData);
if(StratIndex == -1 || endIndex == -1)
{
printf("你输入的起点或终点有错 请重新输入\n");
continue;
}
//对相应位置的进行赋值 这里采用行表示起点 列表示终点
G->A[StratIndex][endIndex] = w;
}
for(i = 0;i < G->VexNum;i++)
{
for(j = 0;j < G->VexNum;j++)
{
printf("%d\t",G->A[i][j]);
}
printf("\n");
}
return G;
}
char visited[VMAX] = {FALSE};//0表示未被访问 1表示被访问了
/*
func:获取下一个邻接点
G你从那个图的顶点集合搜索 vi你搜索谁的邻接点 V你这一次从第几列开始搜索
*/
int GetNextApp(MyGragh *G,int vi,int v)
{
for(int i = v;i < G->VexNum;i++)
{
//如果vi到i顶点对应的权值不为无穷大 意味着这是它的邻接点
if(G->A[vi][i] != INT_MAX)
{
return i;
}
}
return -1;
}
void DFS(MyGragh *G,int vi)
{
int v = 0;
if(visited[vi] == FALSE)
{
myVisit(G,vi);
visited[vi] = TRUE;
for(v = GetNextApp(G,vi,v);v != -1;v = GetNextApp(G,vi,v+1))
{
if(visited[v] == FALSE)
{
myVisit(G,v);
visited[v] = TRUE;
DFS(G,v);
}
}
}
}
//按照深度优先的规则访问图G
void DFSTravers(MyGragh *G)
{
//重置visited
for(int i = 0;i <VMAX;i++)
{
visited[i] = FALSE;
}
for(int i = 0;i < G->VexNum;i++)
{
if(visited[i] == FALSE)
{
//深度优先搜索的方式访问这个顶点
DFS(G,i);
}
}
printf("\n");
}
void BFSTravers(MyGragh *G)
{
//重置visited
for(int i = 0;i <VMAX;i++)
{
visited[i] = FALSE;
}
LinkedQueue *myQueue = InitQueue();
for(int v0 = 0;v0 < G->VexNum;v0++)
{
if(visited[v0] == FALSE)
{
myVisit(G,v0);
visited[v0] = TRUE;
EnQueue(myQueue,v0);
while(QueueIsEmpty(myQueue) == 0)
{
int vi = 0;
int v = 0;;
DeQueue(myQueue,&vi);
//依次访问出队顶点的所有邻接点,并入队
for(v = GetNextApp(G,vi,v);v != -1;v = GetNextApp(G,vi,v+1))
{
if(visited[v] == FALSE)
{
myVisit(G,v);
visited[v] = TRUE;
EnQueue(myQueue,v);
}
}
}
}
}
}
//------------------
//------------------
//main.c
#include <stdio.h>
#include "Gragh.h"
int main()
{
MyGragh *G = CreateGraph();
//DFSTravers(G);
BFSTravers(G);
//printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
return 0;
}
//-----------------------
//被引用的队列相关代码
//-----------------------
//LinkedQueue.h
#ifndef __LINKEDQUEUE_H__
#define __LINKEDQUEUE_H__
typedef int QElemType;
typedef struct QueueNode
{
QElemType data;
struct QueueNode *ptNext;
}QueueNode;
typedef struct LinkedQueue
{
QueueNode *ptFront;
QueueNode *ptRear;
int dwCount;
/*
其他的看你需要什么了
*/
}LinkedQueue;
//初始化一个队列 返回值返回队列的指针
LinkedQueue *InitQueue();
//清空一个队列
//warning:清空队列会把队列保存地址的空间给释放掉!!
//void ClearQueue_Free(LinkedQueue * ptQueue);
//清空一个队列
//warning:清空队列不会把队列保存地址的空间给释放掉!!
void ClearQueue_NoFree(LinkedQueue * ptQueue);
//销毁一个队列
//warning:销毁队列会把队列保存地址的空间给释放掉!!
//void DestroyQueue_Free(LinkedQueue * ptQueue);
//销毁一个队列
//warning:销毁队列不会会把队列保存地址的空间给释放掉!!
void DestroyQueue_NoFree(LinkedQueue * ptQueue);
//判断一个队列是否为空
//返回值 1 为空
// 0 非空
int QueueIsEmpty(LinkedQueue * ptQueue);
//判断队列中元素的个数 即队列的长度
//判断一个队列是否为空
//返回值 -1 失败
// >= 表示长度
int QueueLength(LinkedQueue * ptQueue);
/*
入队
data表示要入队的元素
返回值 0 成功
-1 失败
*/
int EnQueue(LinkedQueue * ptQueue,QElemType data);
/*
出队
data表示要出队的元素
返回值 0 成功
-1 失败
*/
int DeQueue(LinkedQueue * ptQueue,QElemType *data);
//获取队头元素但是不出队
/*
获取队头元素但是不出队
data表示要队头的元素
返回值 0 成功
-1 失败
*/
int GetHead(LinkedQueue * ptQueue,QElemType *data);
#endif
//-------------
//--------------
//LinkedQueue.c
#include <stdio.h>
#include <stdlib.h>
#include "LinkedQueue.h"
LinkedQueue *InitQueue(int dwQueueMaxLength)
{
LinkedQueue *ptLinkedQueue = (LinkedQueue*)malloc(sizeof(LinkedQueue));
ptLinkedQueue->dwCount = 0;
ptLinkedQueue->ptFront = NULL;
ptLinkedQueue->ptRear = NULL;
}
void ClearQueue_Free(LinkedQueue * ptQueue)
{
// if(ptQueue == NULL)
// {
// return ;
// }
// QElemType data;
// while(!QueueIsEmpty(ptQueue))
// {
// DeQueue(ptQueue,&data);
// //通用栈存的是一个地址,清空栈的时候需要释放
// free(data);
// }
}
void ClearQueue_NoFree(LinkedQueue * ptQueue)
{
if(ptQueue == NULL)
{
return ;
}
QElemType data;
while(!QueueIsEmpty(ptQueue))
{
DeQueue(ptQueue,&data);
}
}
void DestroyQueue_Free(LinkedQueue * ptQueue)
{
if(ptQueue == NULL)
{
return ;
}
ClearQueue_Free(ptQueue);
free(ptQueue);
}
void DestroyQueue_NoFree(LinkedQueue * ptQueue)
{
if(ptQueue == NULL)
{
return ;
}
ClearQueue_NoFree(ptQueue);
free(ptQueue);
}
int QueueIsEmpty(LinkedQueue * ptQueue)
{
if(ptQueue == NULL)
{
return -1;
}
return (ptQueue->dwCount == 0)?1:0;
}
int QueueLength(LinkedQueue * ptQueue)
{
if(ptQueue == NULL)
{
return -1;
}
return ptQueue->dwCount;
}
int EnQueue(LinkedQueue * ptQueue,QElemType data)
{
if(ptQueue == NULL)
{
return -1;
}
//创建节点并保存
QueueNode *p = (QueueNode *)malloc(sizeof(QueueNode));
p->data = data;
p->ptNext = NULL;
//入队
//队中没有元素
if(ptQueue->ptFront == NULL)
{
ptQueue->ptFront = p;
}
else//有至少一个元素 尾插法
{
ptQueue->ptRear->ptNext = p;
}
ptQueue->ptRear = p;
ptQueue->dwCount ++;
return 0;
}
int DeQueue(LinkedQueue * ptQueue,QElemType *data)
{
//安全检查
if(ptQueue == NULL || ptQueue->dwCount == 0)
{
return -1;
}
//返回队头的值
*data = ptQueue->ptFront->data;
//删除队头
QueueNode *p = ptQueue->ptFront;
ptQueue->ptFront = p->ptNext;
//队头已经为空 没有元素了 队尾也要为空
if(ptQueue->ptFront == NULL)
{
ptQueue->ptRear = NULL;
}
ptQueue->dwCount--;
p->ptNext = NULL;
free(p);
return 0;
}
int GetHead(LinkedQueue * ptQueue,QElemType *data)
{
//安全检查
if(ptQueue == NULL || ptQueue->dwCount == 0)
{
return -1;
}
//返回队头的值
*data = ptQueue->ptFront->data;
return 0;
}
//-----------------------
最短路径问题
dijikstra 迪杰斯特拉
单源最短路径算法 其目的是求解出从一个点出发到其他所有点的最短路径
采用的是贪心策略 不能出现负权值
Floyd 弗洛伊德算法
多元最短路径算法 采用了动态规划的思想 求解的是图中所有点到任意点到最短路径
迪杰斯特拉算法思路:
1.更新 :更新distance数组和path数组 计算从起点出发经过第三步的添加的中转到各点的距离
如果距离更短,则更新为更短的距离和路径 否则保留原址
2.扫描 找出未找到最短路径的点中距离最小的那个,这个点就是新的最短路径
3.添加 将新的那个点作为搜索的中转点,将对应visit置为ture
循环n遍
迪杰斯特拉具体代码:
//在前面BFS算法上面相应文件上面添加代码
//------------------
//Gragh.h
void Dijkstra(MyGragh *G,int v0);
//------------------
//------------------
//Gragh.c
void Dijkstra(MyGragh *G,int v0)
{
//初始化
char IsShortestPath[VMAX] = {FALSE};
for(int i = 0;i < G->VexNum;i++)
{
IsShortestPath[i] = FALSE;
}
int distance[VMAX] = {INT_MAX};
for(int i = 0;i < G->VexNum;i++)
{
distance[i] = INT_MAX;
}
char path[VMAX] = {-1};
for(int i = 0;i < G->VexNum;i++)
{
path[i] = -1;
}
IsShortestPath[v0] = TRUE;
distance[v0] = 0;
path [v0] = v0;
printf("\n");
//寻找从v0出发到各点的最短路径
int i = 0;
int Intrm = v0;//中转点 从起点出发经过该点到各点
int minDistance = INT_MAX;
int v= 0;//表示邻接点
while(i++ < G->VexNum)
{
//1.更新
for(v = GetNextApp(G,Intrm,v);v != -1; v = GetNextApp(G,Intrm,v+1))
{
//如果经过该点到邻接点v距离更短,则更新新的路径
if(distance[Intrm] + G->A[Intrm][v] < distance[v])
{
distance[v] = distance[Intrm] + G->A[Intrm][v];
path[v] = Intrm;
}
}
//2.扫描
minDistance = INT_MAX;
for(int i = 0;i < G->VexNum;i++)
{
if(IsShortestPath[i] == FALSE)
{
if(distance[i] < minDistance)
{
minDistance = distance[i];
Intrm = i;
}
}
}
//3.添加
IsShortestPath[Intrm] = TRUE;
}
//把结果打印出来
int j = 0;
for(int vi = 0; vi < G->VexNum;vi++)
{
if(vi == v0)
{
continue;
}
printf("%d -> %d 最短的距离是:%d\n",v0,vi,distance[vi]);
j = vi;
//起点的最短路径是它本身 所以j == path[j] 就表示已经找到起点了
printf("路径为:");
while(j != path[j])
{
printf("%d <- ",j);
j = path[j];
}
printf("%d\n",j);
}
}
//--------------------
//--------------------
//main.c
int main()
{
MyGragh *G = CreateGraph();
//DFSTravers(G);
//BFSTravers(G);
//printf("%s %s %d\n",__FILE__,__FUNCTION__,__LINE__);
Dijkstra(G,0);
return 0;
}
//-------------------