数据结构伪C代码:7.图

//--------------------图的数组(邻接矩阵)存储表示--------------------
#define INFINITY  INT_MAX  //最大值无穷
#define MAX_VERTEX_NUM 20  //最大顶点个数
typedef enum {DG,DN,UDG,UDN} GraphKind; //{有向图,有向网,无向图,无向网}
typedef struct ArcCell{
	  VRType  adj;   //VRType是顶点关系类型。对无权图,用1或0表示相邻否;
	                 //对带权图,则为权值类型
	  InfoType *info;//该弧相关信息的指针
	}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
	  VertexType  vexs[MAX_VERTEX_NUM];    //顶点向量
	  AdjMatrix  arcs;                     //邻接矩阵
	  int  vexnum,arcnum;                  //图的当前顶点数和弧数
	  GraphKind kind;                      //图的种类标志
	}MGraph;
//算法7.1
status CreateGraph(MGraph &G){
	//采用数组(邻接矩阵)表示法,构造图G
	  scanf(&G.kind);
	  switch(G.kind){
	  	  case DG:return CreateDG(G);  //构造有向图
	  	  case DN:return CreateDN(G);  //构造有向网
	  	  case UDG:return CreateUDG(G);//构造无向图
	  	  case UDN:return CreateUDN(G);//构造无向网
	  	  default: return error;
	  	}
	}
//算法7.2
status CreateUDN(MGraph &G){
	//采用数组(邻接矩阵)表示法,构造无向网G
	  scanf(&G.vexnum,&G.arcnum,&IncInfo);  //IncInfo为0则各弧不含其它信息
	  for(i=0;i<G.vexnum;i++)
	    //构造顶点向量
	    scanf(&G.vexs[i]);
	  for(i=0;i<G.vexnum;i++)  //初始化邻接矩阵
	    for(j=0;j<G.vexnum;j++)
	      G.arcs[i][j]={INFINITY,NULL}; //{adj,info}
	  for(k=0;k<G.arcnum;k++){     //构造邻接矩阵
	  	  scanf(&v1,&v2,&w);       //输入一条边依附的顶点及权值
	  	  i=LocateVex(G,v1);
	  	  j=LocateVex(G,v2);       //确定v1和v2在G中位置
	  	  G.arcs[i][j].adj=w;   
	  	  if(IncInfo)
	  	  	 Input(*G.arcs[i][j].info);  //若弧含有相关信息,则输入
	  	  G.arcs[j][i]=G.[i][j];
	  	}
	 return ok;
	}
//------------------------图的邻接表存储表示-------------------
#define MAX_VERTEX_NUM  20
typedef struct ArcNode{
	   int   adjvex;        //该弧所指向的顶点的位置
	   struct ArcNode *nextarc;//指向下一条弧的指针
	   InfoType  *info;     //该弧相关信息的指针
	}ArcNode;
typedef struct VNode{
	   VertexType data;  //顶点信息
	   ArcNode *firstarc;//指向第一条依赖该顶点的弧的指针
	}VNode,AdjList[MAX_VERTEX_NUM];
typedef struct{
	  AdjList  vertices;
	  int vexnum,arcnum;     //图的当前顶点数和弧数
	  int kind;              //图的种类标志
	}ALGraph;
//------------------------有向图的十字链表存储表示------------
#define MAX_VERTEX_NUM  20
typedef struct ArcBox{
	  int  tailvex,headvex;   //该弧的尾和头顶点的位置
	  struct ArcBox *hlink,*tlink;//分别为弧头相同和弧尾相同的弧的链域
	  InfoType  *info;        //该弧相关信息的指针
	}ArcBox;
typedef struct VexNode{
	   VertexType data;
	   ArcBox *firstin,*firstout;//分别指向该顶点第一条入弧和出弧
	}VexNode;
typedef struct{
	   VexNode xlist[MAX_VERTEX_NUM];  //表头向量
	   int vexnum,arcnum;
	}OLGraph;
//算法7.3
status CreateDG(OLGraph &G){
	//采用十字链表存储表示,构造有向图G
	   scanf(&G.vexnum,&G.arcnum,&IncInfo);
	   for(i=0;i<G.vexnum;i++){       //构造表头向量
	   	   scanf(&G.xlist[i].data);   //输入顶点值
	   	   G.xlist[i].firstin=NULL;   //初始化指针
	   	   G.xlist[i].firstout=NULL;
	   	}
	   for(k=0;k<G.arcnum;k++){       //输入各弧并构造十字链表
	   	  scanf(&v1,&v2);             //输入一条弧的始点和终点
	   	  i=LocateVex(G,v1);
	   	  j=LocateVex(G,v2);          //确定v1和v2在G中的位置
	   	  p=(ArcBox *)malloc(sizeof(ArcBox));//假定有足够空间
	   	  *p={i,j,G.xlist[j].firstin,G.xlist[i].firstout,null};// 对弧结点赋值
	   	  //{tailvex,headvex,hlink,tlink,info}
	   	  G.xlist[j].firstin=G.xlist[i].firstout=p;//完成在入弧和出弧链头的插入
	   	  if(IncInfo)
	   	  	 Input(*p->info);       //若弧含有信息,则输入
	   	}
	}
//-----------------------无向图的邻接多重表存储表示---------
#define MAX_VERTEX_NUM  20
typedef emnu{unvisited,visited} VisitIf;
typedef struct EBox{
	  VisitIf   mark;         //访问标记
	  int ivex,jvex;          //该边依附的两个顶点的位置
	  struct EBox *ilink,*jlink;//分别指向依附这两个顶点的下一条边
	  InfoType *info;         //该边信息指针
	}EBox;
typedef struct {
	   VexBox  adjmulist[MAX_VERTEX_NUM];
	   int vexnum,edgenum;    //无向图的当前顶点数和边数
	}AMLGraph;
//算法7.4,7.5使用的全局变量===================
Boolean visited[MAX];         //访问标志数组
status(*visitFunc)(int v);    //函数变量
//算法7.4
void DFSTraverse(Graph G,status(*visit)(int v)){
	//对图G作深度优先遍历
	   visitFunc=visit;  //使用全局变量visitFunc,使DFS不必设函数指针参数
	   for(v=0;v<G.vexnum;v++)
	      visited[v]=FALSE;   //访问标志数组初始化
	   for(v=0;v<G.vexnum;v++)
	      if(!visited[v])
	      	  DFS(G,v);      //对尚未访问的顶点调用DFS
	}
//算法7.5
void DFS(Graph G,int v){
	//从第v个顶点出发递归的深度优先遍历图G
	    visited[v]=TRUE;
	    visitFunc(v);  //访问第v个顶点
	    for(w=FirstAdjVex(G,v);w>=0; w=NextAdjVex(G,v,w))    //w>=0表示存在邻接点
	       if(!visited[w])
	       	 DFS(G,w);     //对v的尚未访问的邻接顶点w递归调用DFS
	}
//算法7.6
void BFSTraverse(Graph G,status(*visit)(int v)){
	//按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited
	   for(v=0;v<G.vexnum;v++)
	     visited[v]=FALSE;
	   InitQueue(Q);    //置空的辅助队列Q
	   for(v=0;v<G.vexnum;v++)
	      if(!visited[v]){        //v尚未访问
	      	  visited[v]=TRUE;
	      	  visite(v);
	      	  EnQueue(Q,v);       //v入队列
	      	  while(!QueueEmpty(Q)){
	      	  	   DeQueue(Q,u);  //对头元素出队并置为u
	      	  	   for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
	      	  	     if(!visited[w]){    //w为u的尚未访问的邻接顶点
	      	  	     	  visited[w]=TRUE;
	      	  	     	  visit(w);
	      	  	     	  EnQueue(Q,w);
	      	  	     	}
	      	  	}
	      	}
	}
//算法7.7
void DFSTorest(Graph G,CSTree &T){
	//建立无向图G的深度优先生成森林的(最左)孩子(右)兄弟链表T
	   T=NULL;
	   for(v=0;v<G.vexnum;v++)
	      visited[v]=FALSE;
	   for(v=0;v<G.vexnum;v++)
	      if(!visited[v]){                       //第v顶点为新的生成树的根结点
	      	  p=(CSTree)malloc(sizeof(CSNode));  //分配根结点
	      	  *p={GetVex(G,v),NULL,NULL};        //给该结点赋值
	      	  if(!T)                             
	      	  	T=p;                             //是第一颗生成树的根(T的根)
	      	  else 
	      	  	q->nextsibling=p;                //是其他生成树的根(前一棵的根的“兄弟”)
	      	  q=p;                               //q指示当前生成树的根
	      	  DFSTree(G,v,p);                    //建立以p为根的生成树
	      	}
	}
//算法7.8
void DFSTree(Graph G,int v,CSTree &T){
	//从第v个顶点出发深度优先遍历图G,建立以T为根的生成树
	    visited[v]=TRUE;
	    first=TRUE;
	    for(w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
	      if(!visited[w]){
	      	   p=(CSTree)malloc(sizeof(CSNode));        //分配孩子结点
	      	   *p={GetVex(G,w),NULL,NULL};
	      	   if(first){                               //w是v的第一个未被访问的邻接顶点
	      	   	   T->lchild=p;                         //是根的左孩子结点
	      	   	   first=FALSE;
	      	   	}
	      	   else{                          
	      	   	   q->nextsibling=p;                    //是上一邻接顶点的右兄弟结点
	      	   	}
	      	  q=p;
	      	  DFSTree(G,w,q);                          //从第w个顶点出发深度优先遍历图G,建立子生成树q
	      	}
	}
//算法7.9
void MiniSpanTree_PRIM(MGraph G,VertexType u){
	//用普里姆算法从第u个顶点出发构造网G的最小生成树T,输出T的各条边、
//	记录从顶点集U到V-U的代价最小的边的辅助数组定义:
//	struct{
//		  VertexType  adjvex;
//		  VRType     lowcost;
//		}closedge[MAX_VERTEX_NUM];
      k=LocateVex(G,u);
      for(j=0;j<G.vexnum;j++)     //辅助数组初始化
        if(j!=k)
        	closedge[j]={u,G.arcs[k][j].adj}; //{adjvex,lowcost}
      closedge[k].lowcost=0;   //初始,U={u}
      for(i=1;i<G.vexnum;i++)  //选择其余G.vexnum-1个顶点
        {
        	k=minimum(closedge); //求出T的下一个结点:第k顶点
        	//此时closedge[k].lowcost=MIN{closedge[vi].lowcost|closedge[vi].lowcost>0,vi属于V-U
        	printf(closedge[k].adjvex,G.vexs[k]); //输出生成树的边
        	closedge[k]=0;     //第k顶点并入U集
        	for(j=0;j<G.vexnum;j++){
        		  if(G.arcs[k][j].adj<closedge[j].lowcost)  //新顶点并入U后重新选择最小边
        		  	closedge[j]={G.vexs[k],G.arcs[k][j].adj};
        		}
        	}
	}
//算法7.10
void FindArticul(ALGraph G){
  //连通图G以邻接表作存储结构,并查找输出G上全部关节点。全局量count对访问计数
    count=1;
    visited[0]=1;           //设定邻接表上0号顶点为生成树的根
    for(i=1;i<G.vexnum;i++)
      visited[i]=0;        //其余顶点尚未访问
    p=G.vertices[0].firstarc;
    v=p->adjvex;
    DFSArticul(G,v);      //从第V顶点出发深度优先查找关节点
    if(count<G.vexnum){   //生成树的根有至少两颗子树
    	  printf(0,G.vertices[0].data);//根是关节点,输出
    	  while(p->nextarc){
    	  	  p=p->nextarc;
    	  	  v=p->adjvex;
    	  	  if(visited[v]==0)
    	  	  	DFSArticul(G,v);
    	  	}
    	}
	}
//算法7.11
void DFSArticul(ALGraph G,int v0){
	//从v0个顶点出发深度优先遍历图G,查找并输出关节点
	   visited[v0]=min=++count;    //v0是第count个访问的顶点
	   for(p=G.vertices[v0].firstarc;p;p=p->nextarc){ //对v0的每个邻接顶点检查
	   	   w=p->adjvex;           //w为v0的邻接顶点
	   	   if(visited[w]==0){     //w未曾访问,是v0的孩子
	   	   	  DFSArticul(G,w);    //返回前求得low[w]
	   	   	  if(low[w]<min)
	   	   	  	 min=low[w];
	   	   	  if(low[w]>=visited[v0])
	   	   	  	printf(v0,G.vertices[v0].data); //关节点
	   	   	}
	   	  else if(visited[w]<min)
	   	  	 min=visited[w];  //w已访问,w是v0在生成树上的祖先
	   	}
	  low[v0]=min;
	}
//算法7.12
status TopologicalSort(ALGraph G){
	//有向图G采用邻接表存储结构
	//若G无回路,则输出G的顶点的一个拓扑序列并返回ok,否则error
	   FindInDegree(G,indegree);     //对各顶点求入度indegree[0..vernum-1]
	   InitStack(S);
	   for(i=0;i<G.vexnum;i++)      //建零入读顶点栈S
	      if(!indegree[i])          //入度为0者进栈
	      	 Push(S,i);
	   count=0;                    //对输出顶点计数
	   while(!StackEmpty(S)){
	   	  Pop(S,i);               //输出i号顶点并计数
	   	  printf(i,G.vertices[i].data);
	   	  count++;
	   	  for(p=G.vertices[i].firstarc;p;p=p->nextarc){
	   	  	  k=p->adjvex;       //对i号顶点的每个邻接点的入度减1
	   	  	  if(!(--indegree[k]))  //入度减为0,则入栈
	   	  	  	Push(S,k);
	   	  	}
	   	}
	  if(count<G.vexnum)
	  	 return error;      //该有向图有回路
	  else
	  	 return ok;
	}
//算法7.13
status TopologicalOrder(ALGraph G,Stack &T){
	//有向网G采用邻接表存储结构,求各顶点事件的最早发生时间ve(全局变量)
	//T为拓扑序列顶点栈,S为零入度顶点栈
	//若G无回路,则用栈T返回G的一个拓扑序列,且函数值为ok,否则为error
	   FindInDegree(G,indegree);
	   建零入度顶点栈S;
	   InitStack(T);
	   count=0;
	   ve[0..G.vexnum-1]=0;
	   while(!StackEmpty(S)){
	   	  Pop(S,j);
	   	  Push(T,j);
	   	  count++;
	   	  for(p=G.vertices[j].firstarc;p;p=p->nextarc){
	   	  	   k=p->adjvex;
	   	  	   if(--indegree[k]==0)
	   	  	   	  Push(S,k);
	   	  	   if(ve[j]+*(p->info)>ve[k])
	   	  	   	  ve[k]=ve[j]+*(p->info);
	   	  	}
	   	}
	  if(count<G.vexnum)
	  	  return error;
	  else
	  	  return ok;
	}
//算法7.14
status CriticalPath(ALGraph){
	//G为有向网,输出G的各项关键活动
	  if(!TopologicalOrder(G,T))
	  	  return error;
	  vl[0...G.vexnum-1]=ve[G.vexnum-1];   //初始化顶点事件的最迟发生时间
	  while(!StackEmpty(T))                //按拓扑逆序求各顶点的vl值
	     for(Pop(T,j),p=G.vertices[j].firstarc;p;p=p->nextarc){
	     	  k=p->adjvex;
	     	  dut=*(p->info);      //dut<j,k>
	     	  if(vl[k]-dut<vl[j])
	     	  	  vl[j]=vl[k]-dut;
	     	}
	    for(j=0;j<G.vexnum;j++)     //求ee,el和关键活动
	      for(p=G.vertices[j].firstarc;p;p=p->nextarc){
	      	  k=p->adjvex;
	      	  dut=*(p->info);
	      	  ee=ve[j];
	      	  el=vl[k]-dut;
	      	  tag=(ee==el)?'*':' ';
	      	  	printf(j,k,dut,ee,el,tag);  //输出关键活动
	      	}
	}
//算法7.15
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix &p,ShortPathTable &D){
	//用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及其带权长度D[v]
	//若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点
	//final[v]为TRUE当且仅当v属于S,即已经求得从v0到v的最短路径
	  for(v=0;v<G.vexnum;v++){
	  	  final[v]=FALSE;
	  	  D[v]=G.arcs[v0][v];
	  	  for(w=0;w<G.vexnum;w++)
	  	     P[v][w]=FALSE;   //设空路径
	  	  if(D[v]<INFINITY){
	  	  	   P[v][v0]=TRUE;
	  	  	   P[v][v]=TRUE;
	  	  	}
	  	}
	  D[v0]=0;
	  final[v0]=TRUE;//初始化,v0顶点属于S集
	  //开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集
	  for(i=1;i<G.vexnum;i++){   //其余G.vexnum-1个顶点
	  	  min=INFINITY;          //当前所知离v0顶点的最近距离
	  	  for(w=0;w<G.vexnum;w++)
	  	    if(!final[w])        //w顶点在V-S中
	  	    	if(D[w]<min){      //w顶点离v0顶点更近
	  	    		  v=w;
	  	    		  min=D[w];
	  	    		}
	  	  final[v]=TRUE;        //离v0顶点最近的v加入S集
	  	  for(w=0;w<G.vexnum;w++)  //更新当前最短路径及距离
	  	    if(!final[w]&&(min+G.arcs[v][w]<D[w])){  //修改D[w]和P[w],w属于V-S
	  	    	  D[w]=min+G.arcs[v][w];
	  	    	  P[w]=P[v];
	  	    	  P[w][w]=TRUE;   //P[w]=P[v]+P[w]
	  	    	}
	  	}
	}
//算法7.16
void ShortestPath_FLOYD(MGraph G,PathMatrix &p[],DistancMatrix &D){
	 //用Floyd算法求有向网G中各对顶点v和w之间的最短路径P[v][w]及其带权长度D[v][w]
	 //若P[v][w][u]为TRUE,则u是从v到w当前求得最短路径上的顶点
	   for(v=0;v<G.vexnum;v++)   //各对结点之间初始已知路径及距离
	      for(w=0;w<G.vexnum;w++){
	      	    D[v][w]=G.arcs[v][w];
	      	    for(u=0;u<G.vexnum;u++)
	      	      P[v][w][u]=FALSE;
	      	    if(D[v][w]<INFINITY){ //从v到w有直接路径
	      	    	   P[v][w][v]=TRUE;
	      	    	   P[v][w][w]=TRUE;
	      	    	}
	      	}
	  for(u=0;u<G.vexnum;u++)
	     for(v=0;v<G.vexnum;v++)
	        for(w=0;w<G.vexnum;w++)
	           if(D[v][u]+D[u][w]<D[v][w]){//从v经u到w的一条路径更短
	           	  D[v][w]=D[v][u]+D[u][w];
	           	  for(i=0;i<G.vexnum;i++)
	           	    P[v][w][i]=P[v][u][i]||P[u][w][i];
	           	}
	}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值