#include
#include
#include
#include
using namespace std;
typedef char VertexType;//顶点类型
typedef int EdgeType;//边的权重
#define MAXVEX 100//最大顶点数
#define INFINITY 65535//代表无穷
#define MAXEDGE 1000
typedef struct
{
VertexType vexs[MAXVEX];//顶点表
EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵
int numVertexes,numEdges;//当前的顶点数和边数
} MGraph;
拓扑排序&关键路径
求拓扑排序的基本思想:
1)从有向图中选 一个无前驱(入度为0)的顶点输出;
2)将此顶点和以它为起点的孤删除;
3)重复1)和2), 直到不存在无前驱的顶点;
4)若此时输出的顶点数小于有向图中的顶点数,则说明有向图中存在回路,否则输出的顶点的顺序即为一个拓扑序列。
typedef struct EdgeNode//边表结点 (用于拓扑排序)
{
int adjvex;//邻接顶点的下标
int weight;//权,用于关键路径算法
struct EdgeNode *next;//指向下一个邻接点
}EdgeNode;
typedef struct VertexNode//顶点表结点 (用于拓扑排序)
{
int in;//顶点的入度
int data;//顶点的值
EdgeNode *firstedge;//边表的头指针
}VertexNode,AdjList[MAXVEX];
typedef struct//(用于拓扑排序)
{
AdjList adjList;
int numVertexes,numEdges;//顶点数和边数
}graphAdjList,*GraphAdjList;
//拓扑排序,若GL无回路则输出拓扑排序序列并返回true,否则返回false
bool TopologicalSort(GraphAdjList GL)
{
EdgeNode *e;
int i,k,gettop,count=0;//gettop用于储存出栈的数,count用于统计输出顶点的个数
stack s;
for(i=0;inumVertexes;i++)//将入度为0的顶点入栈
{
if(GL->adjList[i].in==0)s.push(i);
}
while(!s.empty())
{
gettop=s.top();
s.pop();
printf("%d -> ",GL->adjList[gettop].data);
count++;
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(!(--GL->adjList[k].in))s.push(k);//若入度为0则入栈,方便下次循环输出
}
}
if(countnumVertexes)return false;//count<顶点数说明存在环
else return true;
}
int *etv,*ltv;//指向earliest time of vertex & latest time of vertex数组的指针
stack s2;//用于储存拓扑序列
//增加了一些代码的拓扑排序,用于寻找关键路径
//若GL无回路则输出拓扑排序序列并返回true,否则返回false
bool TopologicalSort2(GraphAdjList GL)
{
EdgeNode *e;
int i,k,gettop,count=0;//gettop用于储存出栈的数,count用于统计输出顶点的个数
stack s;
for(i=0;inumVertexes;i++)//将入度为0的顶点入栈
{
if(GL->adjList[i].in==0)s.push(i);
}
etv=(int*)malloc(GL->numVertexes*sizeof(int));//创建事件最早发生时间数组
for(i=0;inumVertexes;i++)etv[i]=0;//数组的初始化
while(!s.empty())
{
gettop=s.top();
s.pop();
count++;
s2.push(gettop);//将拓扑序列入栈
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(!(--GL->adjList[k].in))s.push(k);//若入度为0则入栈,方便下次循环输出
if(etv[gettop]+e->weight>etv[k])etv[k]=etv[gettop]+e->weight;
}
}
if(countnumVertexes)return false;//count<顶点数说明存在环
else return true;
}
//寻找关键路径
void CriticalPath(GraphAdjList GL)
{
EdgeNode* e;
int i,gettop,k,j;
int ete,lte;//earliest time of edge & latest time of edge
TopologicalSort(GL);
ltv=(int*)malloc(GL->numVertexes*sizeof(int));
for(i=0;inumVertexes;i++)ltv[i]=etv[GL->numVertexes-1];//数组的初始化
while(!s2.empty())
{
gettop=s2.top();
s2.pop();
for(e=GL->adjList[gettop].firstedge;e;e=e->next)
{
k=e->adjvex;
if(ltv[k]-e->weightweight;
}
}
for(j=0;jnumVertexes;j++)
{
for(e=GL->adjList[j].firstedge;e;e=e->next)
{
k=e->adjvex;
ete=etv[j];
lte=ltv[k]-e->weight;
if(ete==lte)
printf(" length:%d\n",GL->adjList[j].data,GL->adjList[k].data,e->weight);
}
}
}
最短路径
typedef int Patharc[MAXVEX];//储存最短路径(用于Dijkstra算法寻找最短路径)
typedef int ShortPathTable[MAXVEX];//储存从起点到各点的最短路径的权值和(用于Dijkstra算法寻找最短路径)
typedef int Patharc1[MAXVEX][MAXVEX];//储存最短路径(用于Floyd算法寻找最短路径)
typedef int ShortPathTable1[MAXVEX][MAXVEX];//储存从起点到各点的最短路径的权值和(用于Floyd算法寻找最短路径)
//Floyd算法求最短路径
void ShortestPath_Floyd(MGraph *G,Patharc1 *P,ShortPathTable1 *D)
{
int v,w,k;
for(v=0;vnumVertexes;v++)//初始化D和P
{
for(w=0;wnumVertexes;w++)
{
(*D)[v][w]=G->arc[v][w];
(*P)[v][w]=w;
}
}
for(k=0;knumVertexes;k++)//k为中转顶点的下标
{
for(v=0;vnumVertexes;v++)//v为起点
{
for(w=0;wnumVertexes;w++)//w是终点
{
if((*D)[v][w]>(*D)[v][k]+(*D)[k][w])
{
(*D)[v][w]=(*D)[v][k]+(*D)[k][w];
(*P)[v][w]=(*P)[v][k];
}
}
}
}
//打印最短路径
printf("各顶点间最短路径如下:\n");
for(v=0;vnumVertexes;v++)
{
for(w=v+1;wnumVertexes;w++)
{
printf("v%d-v%d weight:%d",v,w,(*D)[v][w]);
k=(*P)[v][w];// 获得第一个路径顶点下标
printf(" path: %d",v);//打印源点
while(k!=w)
{
printf(" ->%d",k);//打印路径顶点
k=(*P)[k][w];//获得下一个路径顶点的下标
}
printf(" ->%d\n",w);//打印终点
}
printf("\n");
}
}
//Dijkstra算法求最短路径及相应的长度
//*P[v]为前驱点下标,D[v]表示从v0到v的最短路径长度
void ShortestPath_Dijkstra(MGraph *G,int v0,Patharc P,ShortPathTable D)
{
int v,w,k,min;
int final[MAXVEX];//final[w]=1 表示已经求得v0和vw的最短路径
for(v=0;vnumVertexes;v++)//初始化
{
final[v]=0;//全部顶点初始化为未知最短路径状态
D[v]=G->arc[v0][v];//将与v0有连线的顶点加上权值
P[v]=-1;//初始化路径数组为-1
}
D[v0]=0;
final[v0]=1;
//每次循环求得起点v0到顶点V的最短路径
for(v=1;vnumVertexes;v++)
{
min=INFINITY;
for(w=0;wnumVertexes;w++)//寻找离v0最近且尚未找到最短路径的顶点
{
if(!final[w]&&D[w]numVertexes;w++)///修正当前的最短路径及距离
{
if(!final[w]&&(min+G->arc[k][w]arc[k][w];
P[w]=k;
}
}
}
}
最小生成树
//Prim算法生成最小生成树
void MiniSpanTree_Prim(MGraph *G)
{
int min,i,j,k;
int adjvex[MAXVEX];//保存相关顶点间边的权值点下标
int lowcost[MAXVEX];//保存相关顶点间边的权值
lowcost[0]=0;//初始化第一个权值为0,即将v0加入生成树
adjvex[0]=0;//初始化第一个顶点下标为0
for(i=1;inumNodes;i++)//遍历除下标为0外的所有顶点
{
lowcost[i]=G->arc[0][i];//v0与其他顶点的权值存入数组
adjvex[i]=0;//初始化都为v0的下标 ?????
}
for(i=1;inumNodes;i++)
{
min=INFINITY;
j=1;k=0;
while(jnumNodes)//整个while循环的作用:找到与已联通结点相连的、不会形成环路的最短边
{
if(lowcost[j]!=0&&lowcost[j]numNodes;j++)
{
if(lowcost[j]!=0&&G->arc[k][j]arc[k][j];//将较小的权值存入lowcost相应位置
adjvex[j]=k;//将下标为k的顶点存入adjvex
}
}
}
}
typedef struct //边集数组 (用于Kruskal算法)
{
int begin;
int end;
int weight;
}Edge;
//(用于Kruskal算法)查找连线顶点的尾部下标
int Find(int *parent,int f)
{
while(parent[f]>0)
{
f=parent[f];
}
return f;
}
//Kruskal算法生成最小生成树
void MiniSpanTree_Kruskal(MGraph *G)
{
int i,n,m;
Edge edges[MAXEDGE];//边集数组,其中的元素按照权值从小到大排序
int parent[MAXVEX];//判断边与边是否形成回路,下标和储存的值分别代表边的起点和终点
//省略将邻接矩阵转换为边集数组并排序的过程
for(i=0;inumNodes;i++)
parent[i]=0;//初始化
for(i=0;inumEdges;i++)
{
n=Find(parent,edges[i].begin);
m=Find(parent,edges[i].end);
if(n!=m)//n!=m说明此边没有和现有的生成树形成环路
{
parent[n]=m;//将结尾顶点放入下标为起点的parent中,表示该边已经在生成树里
printf("(%d,%d) %d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
DFS(深度优先搜索 )&BFS(广度优先搜索)
bool visited[MAXVEX];//记录结点是否被访问过 (用于DFS&BFS)
void DFS(MGraph *G,int i)
{
int j;
visited[i]=true;
printf("%c ",G->vexs[i]);
for(j=0;jnumNodes;j++)
{
if(G->arc[i][j]==1&&!visited[j])
DFS(G,j);
}
}
void DFSTraverse(MGraph *G)
{
int i;
for(i=0;inumNodes;i++)
visited[i]=false;
for(i=0;inumNodes;i++)//如果是连通图则本循环只执行一次
if(!visited[i]) DFS(G,i);
}
void BFSTraverse(MGraph *G)
{
int i,j;
queue Q;
for(i=0;inumNodes;i++)
visited[i]=false;
Q.pop();
for(i=0;inumNodes;i++)
{
if(!visited[i])
{
visited[i]=true;
printf("%c ",G->vexs[i]);
Q.push(i);
while(!Q.empty())
{
Q.pop();
for(j=0;jnumNodes;j++)
{
if(G->arc[i][j]==1&&!visited[j])
{
visited[j]=true;
printf("%c ",G->vexs[j]);
Q.push(j);
}
}
}
}
}
}
创建无向图的邻 接矩阵
//创建无向图的邻接矩阵
void CreateMGragh(MGraph *G)
{
int i,j,k,w;
printf("依次输入顶点数和边数:\n");
scanf("%d %d",&G->numNodes,&G->numEdges);
for(i=0;inumNodes;i++)
scanf(&G->vexs[i]);//建立顶点表
//上面这行看不懂
for(i=0;inumNodes;i++)
for(j=0;jnumNodes;j++)
G->arc[i][j]=INFINITY;//邻接矩阵初始化
for(k=0;knumNodes;k++)
{
printf("输入边(vi,vj)的下标i,下标j和权w,中间用空格分隔:\n");
scanf("%d %d %d",&i,&j,&w);
G->arc[i][j]=w;
G->arc[j][i]=w;
}
}
联系之前的文章:广度优先搜索(BFS)寻找最短路径_mirrorboat的博客-CSDN博客#include