//--------------------图的数组(邻接矩阵)存储表示--------------------
#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];
}
}
数据结构伪C代码:7.图
最新推荐文章于 2022-11-14 18:47:41 发布