图(Graph)的基础操作(C++)

#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博客#includeusing namespace std;void EnQueue(int i, int j, int k); //入队一个节点void DeQueue(int* i, int* j, int* k); //获取当前节点的序号和对应的迷宫坐标,然后出列int GetNextPos(int* i, int* j, int count); //得到下一个邻接点的位置void ShortestPath_BFS(int i, int j); //广度优先遍.https://blog.csdn.net/mirrorboat/article/details/122638680?spm=1001.2014.3001.5502

你可能感兴趣的:(数据结构与算法,拓扑学,算法,数据结构)