图的相关操作

 

实现部分:

    //shuju.h的代码//头文件部分

     //图的 邻接表 存储表示

#define MAX_VERTEX_NUM1  10//顶点最大个数

typedef struct ArcNode{

int adjvex;//该弧所指的顶点的位置

struct ArcNode *nextarc;//指向下一条弧的指针

int weight;//边的权

}ArcNode;//表的结点

typedef char VertexType;//顶点元素的类型

typedef struct VNode{

int degree,indegree;//顶点的度 ,入度

VertexType data;    //顶点信息(如数据 等)

ArcNode *firstarc;//指向第一条依附该顶点的弧指针

}VNode,AdjList[MAX_VERTEX_NUM1];//头结点

typedef struct{

AdjList vertices;

int vexnum,arcnum;//顶点的实际数,边()的实际数

int kind;//图的种类

}ALGraph;

#include "GraphRect.h"

void creatLink(ALGraph *G){

//建立邻接链表

int i,j;

ArcNode *s;

printf("输入顶点数,边数:");

scanf("%d%d",&G->vexnum,&G->arcnum);

for(i=0;i<G->vexnum;i++){    

     G->vertices[i].data='A'+i;

     G->vertices[i].firstarc=NULL;

}

printf("Input the adjvexs of arcs /n");//该弧所指的顶点的位置

for(int i1=0;i1<G->arcnum;i1++){

     scanf("%d%d",&i,&j);

     s=(ArcNode*)malloc(sizeof(ArcNode));

     s->adjvex=j;//该弧所指的顶点的位置为 j

     s->nextarc=G->vertices[i].firstarc;

     G->vertices[i].firstarc=s;

}

}

void visit(ALGraph G){

//输出邻接表

int i;

ArcNode *p;

printf("%4s%6s%18s/n","No","data","adjvexs of arcs");

for(i=0;i<G.vexnum;i++){

     printf("%4d% 5c   ",i,G.vertices[i].data);

     for(p=G.vertices[i].firstarc;p;p=p->nextarc)

         printf("%3d",p->adjvex);//弧所指的顶点的位置

     printf("/n");

}

}

void cacu(ALGraph *G){

//计算i个顶点的度及入度

ArcNode*p;

int i;

for(i=0;i<G->vexnum;i++){

     G->vertices[i].degree=0;

     G->vertices[i].indegree=0;

}

for(i=0;i<G->vexnum;i++)

     for(p=G->vertices[i].firstarc;p;p=p->nextarc){

         G->vertices[i].degree++;

         G->vertices[p->adjvex].degree++;

         G->vertices[p->adjvex].indegree++;

     }

}

void printdegree(ALGraph G){

int i;

printf("/n No data deg ind/n");

for(i=0;i<G.vexnum;i++)

     printf("/n%4d% 4c %4d%4d",i,G.vertices[i].data,

     G.vertices[i].degree,G.vertices[i].indegree);

}

Status TopologiSort(ALGraph G){

//拓扑排序--有向图G采用邻接表存储结构

//G无回路,则输出G的顶点的一个拓扑排序并返回OK,否则ERROR

int i,count,top=0,stack[50]={0};

ArcNode *p;

cacu(&G);

printdegree(G);

printf("/n TopologiSort is/n");

for(i=0;i<G.vexnum;i++){//建零入度顶点栈

     if(!G.vertices[i].indegree) {stack[top++]=i;}//入度为零的顶点入栈

}

count=0;                //对输出顶点计数

while(top!=0){

     i=stack[--top];

     if(count==0)printf("%c",G.vertices[i].data);

     else printf("-->%c",G.vertices[i].data);

     count++;            //输出i号顶点并计数

     for(p=G.vertices[i].firstarc;p;p=p->nextarc)

         if(!--G.vertices[p->adjvex].indegree)stack[top++]=p->adjvex;//i号顶点的每个邻接点的入度减1

                                     //若入度为零,则入栈                                               

}//while

printf("/n");

if(count<G.vexnum)return (FALSE);   //该有向图有回路

else return (TRUE);

}//TopologiSort

///

//深度优先搜索需要的函数:firstAdjVex,NextAdjVex,Vvisit

int FirstAdjVex(ALGraph G,int v){

//

ArcNode *p;

if(p=G.vertices[v].firstarc)

     return p->adjvex;

else return -1;

}

int NextAdjVex(ALGraph G,int v,int w){

//

ArcNode *p=G.vertices[v].firstarc;

while(p->adjvex!=w){

     p=p->nextarc;

}

if(p->nextarc)return p->nextarc->adjvex;

else return -1;

}

Status Vvisit(ALGraph G,int v){

//ALGraph G;

VNode p=G.vertices[v];

printf("%c  ",p.data);

return OK;

}

//DFSTraverseDFS使用的全局变量

bool visited[MAX_VERTEX_NUM1];//访问标志数组

Status (*VisitFunc)(ALGraph G,int v);//函数指针

void DFS(ALGraph G,int v){

//从第V个顶点出发递归地深度优先遍历图G

visited[v]=TRUE;

VisitFunc(G,v);//访问第v个顶点

for(int w=FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))

     if(!visited[w])DFS(G,w);//对尚未访问的邻接顶点w递归调用DFS

}

void DFSTraverse(ALGraph G,Status(*Visit)(ALGraph G,int v)){

//对图G进行深度优先遍历

VisitFunc=Visit;//使用全局变量VisitFunc,使DFS不必设函数指针参数

for(int v1=0;v1<G.vexnum;++v1)visited[v1]=FALSE;//访问标志数组初始化

for(int v=0;v<G.vexnum;++v)

     if(!visited[v])DFS(G,v);//对尚未访问的顶点调用DFS

     printf("/n");

}

/

//广度优先搜索

void BFSTraverse (ALGraph G,Status(*Visit)(ALGraph G,int v)){

//安广度优先非递归遍历图G。使用辅助队列Q和访问标志数组visited

int u,w;

for(int v1=0;v1<G.vexnum;++v1)visited[v1]=FALSE;

LinkQueue Q;

InitQueue(Q);           //置空的辅助队列Q

for(int v=0;v<G.vexnum;++v)

     if(!visited[v]){        //v尚未访问

         visited[v]=TRUE;

         (*Visit)(G,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]){    //wu的尚未访问的邻接顶点

                     visited[w]=TRUE;

                     (*Visit)(G,w);

                     EnQueue(Q,w);

                 }//if

         }//while

     }//if

     DestroyQueue(Q);

}//BFSTraverse

//图的存储表示方法(2)保存在GraphRect.h

//图的邻接矩阵表示法(数组存储)//图的十字链表存储

#include"stdio.h"

#include "stdlib.h"

//#include"iomanip.h"//setw(10)

  #define TRUE 1

  #define FALSE 0

  #define OK   1

  #define ERROR  0

  #define INFEASIBLE -1

  #define OVERFLOW -2

  #define NULL 0

  typedef int Status;//函数的类型,其值是函数结果状态代码

 

#define MAX_VERTEX_NUM 20//最大顶点数

#define INFINITY 32768//无穷大

 

typedef int  GraphKind;//有向图,有向网,无向图,无向网

typedef char VertexType;

typedef int VRType;

typedef int InforType;

//typedef bool final ;//当其为TRUE时 表明已求得最短路径

//typedef int **PathMatrix;//顶点的最短路径数组

//typedef int *ShortPathTable;//顶点的最短路径的带权长度数组

typedef struct ArcCell{

VRType adj;//VRType是顶点关系类型,对无权图,用10表示相邻否;对带权图,则为权值类型

InforType *info;//改弧相关信息的指针

}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

typedef struct {

VertexType vexs[MAX_VERTEX_NUM];//顶点向量

AdjMatrix arcs;//邻接矩阵

int vexnum ,arcnum;//图的当前顶点数和弧数

GraphKind kind;//图的种类标志

}MGraph;

int LocateVex(MGraph G,char v){

for(int i=0;v!=G.vexs[i]&&i<G.vexnum;++i);

if(i>=G.vexnum)return -1;

return i;

}

Status CreateUDN(MGraph &G){

//采用数组(邻接矩阵)表示法,构造无向网

int IncInfo=0;

printf("请输入图的种类(有向1,无向0)/n");

scanf("%d",&G.kind);

printf("请输入顶点数vexnum,弧数arcnum和各弧的其他信息IncInfo(默认值0)/n");

scanf("%d%d%d",&G.vexnum,&G.arcnum,&IncInfo);//IncInfo0则各弧不含其它信息

printf("构造顶点向量/n");

for (int i1=0;i1<G.vexnum;++i1)

     scanf("%s",&G.vexs[i1]);//构造顶点向量

for(int i=0;i<G.vexnum;++i)

     for(int j=0;j<G.vexnum;++j){

         G.arcs[i][j].adj=INFINITY;//{adj,info}

         G.arcs[i][j].info=NULL;

     }

     char v1,v2;

     int w;

     for(int k=0;k<G.arcnum;++k){//构造邻接矩阵

         printf("输入一条边依附的顶点和权值v1 v2 w :/n");

         scanf("%s%s%d",&v1,&v2,&w);//输入一条边依附的顶点和权值

         int i=LocateVex(G,v1);

         int j=LocateVex(G,v2);//确定v1v2G中的位置

         G.arcs[i][j].adj=w;//弧的权值

         if(IncInfo)scanf("%d",&G.arcs[i][j].info);//若弧含有相关信息,则输入

         if(!G.kind)G.arcs[j][i].adj=G.arcs[i][j].adj;//<v1,v2>的对称弧<v2,v1>

     }

     return OK;

}//CreateUDN

Status PrintfMGraph(MGraph G){

printf("输出邻接矩阵/n");

for(int i=0;i<G.vexnum;++i){

     printf("%d  %c ||  ",i,G.vexs[i]);

     for(int j=0;j<G.vexnum;++j){

         printf("%5d  ",G.arcs[i][j].adj);

     }

     j=0;

     printf("/n");

}

printf("----------32768代表无穷大----------/n");

return OK;

}

Status ShortestPath_DIJ(MGraph G,VertexType vv,int P[][100],int D[]){

//Dijkstra算法求Gv0到其余顶点v的最短路径及其带权长度D[v]

//P[v][w]TRUE,则w是从v0w的当前最短路径的顶点

//final[v]TRUE时表明已求得最短路径

int v0=LocateVex(G,vv);

int final[10];

for(int v=0;v<G.vexnum;++v){

     final[v]=FALSE;         //当其为TRUE时 表明已求得最短路径

     D[v]=G.arcs[v0][v].adj;

     for(int w=0;w<G.vexnum;++w) P[v][w]=FALSE;//设空路径

     if(D[v]<INFINITY){

         P[v][v0]= TRUE;

         P[v][v]=TRUE;

     }

}//for

D[v0]=0;final[v0]=1;        //初始化,v0顶点属于S

printf("%c v顶点的最短距离及途经顶点/n",vv);

int min=0;                  //开始主循环,每次求得v0到某个v顶点的最短路径,并加vS

for(int i=1;i<G.vexnum;++i){    ///其余G.vexnum1各顶点//循环n-1次结束

     min=INFINITY;           //当前离所知的顶点v0的最近距离

     for(int w1=0;w1<G.vexnum;++w1)

         if(!final[w1])      //w顶点在VS

             if(D[w1]<min){

                 v=w1;

                 min=D[w1];  //w1离顶点v0最近

             }

     final[v]=TRUE;          //v0点最近的v加入S

     printf("/n    %c%8d",G.vexs[v],min);//输出函数部分

     printf("        ");

     for(int j=0;j<G.vexnum;++j)

         if(P[v][j])printf("%c",G.vexs[j]);//输出最短路径上的所有顶点

     for(int w2=0;w2<G.vexnum;++w2)  //更新当前最段路径机距离

         if(!final[w2]&&(min+G.arcs[v][w2].adj<D[w2])){//修改D[w2]P[w2]

             D[w2]=min+G.arcs[v][w2].adj;

             for(int s=0;s<G.vexnum;++s)

             P[w2][s]=P[v][s];

             P[w2][w2]=TRUE;     //P[w2]=P[v]+P[w2]

         }//if

}//for

printf("/n");

return OK;

}

void MiniSpanTree_PRIM(MGraph G,VertexType u){

struct {

     VertexType adjvex;

     VRType lowcost;

}closedge[MAX_VERTEX_NUM];

int k=LocateVex(G,u);

for(int j=0;j<G.vexnum;++j)

     if(j!=k){

         closedge[j].adjvex=u;

         closedge[j].lowcost=G.arcs[k][j].adj;

     }

     closedge[k].lowcost=0;

     printf("Prim 算法输出最小生成树/n");

     for(int i=1;i<G.vexnum;++i){

         int min=INFINITY;

         int k1=0;

         for(int n=0;n<G.vexnum;++n){

             if(closedge[n].lowcost){

                 if(closedge[n].lowcost<min){

                     min=closedge[n].lowcost;

                     k1=n;

                 }

             }

         }

         printf("%c-->%c  ",closedge[k1].adjvex,G.vexs[k1]);

         closedge[k1].lowcost=0;

         for(int j1=0;j1<G.vexnum;++j1)

             if(G.arcs[k1][j1].adj<closedge[j1].lowcost){

                 closedge[j1].lowcost=G.arcs[k1][j1].adj;

                 closedge[j1].adjvex=G.vexs[k1];

             }

     }

     printf("/n");

}

//单链队列 ,队列的链式存储结构

typedef int QElemType;

typedef struct QNode{

QElemType data;

struct QNode *next;

}QNode,*QueuePtr;

typedef struct{

QueuePtr front;

QueuePtr rear;

}LinkQueue;

Status InitQueue(LinkQueue &Q){

Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));

if(!Q.front)exit(OVERFLOW);

Q.front->next=NULL;

return OK;

}

Status QueueEmpty(LinkQueue Q){

if(Q.front==Q.rear)return OK;

else return ERROR;

}

Status EnQueue(LinkQueue &Q,QElemType e){

QueuePtr p=(QueuePtr)malloc(sizeof(QNode));

if(!p)exit(OVERFLOW);

p->data=e;

p->next=NULL;

Q.rear->next=p;

Q.rear=p;

return OK;

}

Status DeQueue(LinkQueue &Q,QElemType &e){

if(Q.front==Q.rear)return ERROR;

QueuePtr p=Q.front->next;

e=p->data;

Q.front->next=p->next;

if(Q.rear==p)Q.rear=Q.front;

free(p);

return OK;

}

Status GetHead(LinkQueue &Q,QElemType &e){

QueuePtr p;

if(QueueEmpty(Q))return 0;

else {

     p=Q.rear;

     return p->data;

}

return OK;

}

Status DestroyQueue(LinkQueue &Q){

while(Q.front){

     Q.rear=Q.front->next;

     free(Q.front);

     Q.front=Q.rear;//从前向后依次删除队列中的结点

}

return OK;

}

//十字链表结构

//有向图无向图的十字链表存储表示

typedef struct ArcBox{

VRType tailvex,headvex;//VRTypeint类型,该弧的尾和头顶点的位置

struct ArcBox *hlink,*tlink;//分别为弧头相同的弧和弧尾相同的弧的链域

InforType *info;//改弧相关信息的指针

}ArcBox;

typedef struct VexNode{

VertexType data;//VRType是顶点关系类型,对无权图,用10表示相邻否;对带权图,则为权值类型

ArcBox *firstin,*firstout;//分别指向该顶点的第一个如入弧和出弧

}VexNode;

typedef struct {

VexNode xlist[MAX_VERTEX_NUM];//顶点向量

int vexnum ,arcnum;//图的当前顶点数和弧数

GraphKind kind;//图的种类标志

}OLGraph;

int LocateVex(OLGraph G,char v){

for(int i=0;v!=G.xlist[i].data&&i<G.vexnum;++i);

if(i>=G.vexnum)return -1;

return i;

}

Status CreateUDG(OLGraph &G){

//采用十字链表表示法,构造无向网

int IncInfo=0;

printf("请输入图的种类(有向1,无向0)/n");

scanf("%d",&G.kind);

printf("请输入顶点数vexnum,弧数arcnum和各弧的其他信息IncInfo(默认值0)/n");

scanf("%d%d%d",&G.vexnum,&G.arcnum,&IncInfo);//IncInfo0则各弧不含其它信息

printf("构造顶点向量/n");

for (int i1=0;i1<G.vexnum;++i1){

     scanf("%s",&G.xlist[i1].data);//构造顶点向量

     G.xlist[i1].firstin=NULL;//初始化指针

     G.xlist[i1].firstout=NULL;

     }

     char v1,v2;

     for(int k=0;k<G.arcnum;++k){//构造十字链表

         printf("输入一条边依附的顶点v1 v2 :/n");

         scanf("%s%s",&v1,&v2);//输入一条边依附的顶点

         int i=LocateVex(G,v1);

         int j=LocateVex(G,v2);//确定v1v2G中的位置

         ArcBox* p=(ArcBox*)malloc(sizeof(ArcBox));

         p->tailvex=i;

         p->headvex=j;

         p->hlink=G.xlist[j].firstin;

         p->tlink=G.xlist[i].firstout;

         p->info=NULL;

         G.xlist[j].firstin  = G.xlist[i].firstout=p;//完成入弧出弧连头的插入

         if(IncInfo)scanf("%d",&(p->info));//若弧含有相关信息,则输入

         if(!G.kind){//<v1,v2>的对称弧<v2,v1>

             ArcBox* q=(ArcBox*)malloc(sizeof(ArcBox));

             q->tailvex=j;

             q->headvex=i;

             q->hlink=G.xlist[i].firstin;

             q->tlink=G.xlist[j].firstout;

             q->info=NULL;

             G.xlist[i].firstin = G.xlist[j].firstout=q;//完成入弧出弧连头的插入

             if(IncInfo)scanf("%d",&(q->info));//若弧含有相关信息,则输入

         }

     }

     return OK;

}//CreateUDG

void visit_OL(OLGraph G){

//输出十字表

int i;

ArcBox *p;

printf("%4s%6s%25s/n","No","data","adjvexs of arcs'tailvex");

for(i=0;i<G.vexnum;i++){

     printf("%4d% 5c   ",i,G.xlist[i].data);

     for(p=G.xlist[i].firstout;p;p=p->tlink)

         printf("%3d",p->headvex);//弧所指的顶点的位置

     printf("/n");

}

}

//主函数部分

//图的主函数部分,文件名为graph.cpp

#include"shuju.h"

void main()

{

ALGraph G1;

int P[100][100];

int D[100];

MGraph G2;

char v0;

v0='a';

OLGraph G;

int select;

while(select){

     printf("1,键盘输入数据,建立一个有向图的邻接表/n");

     printf("2,输出该邻接表/n");

     printf("3,建立一个无向图的十字链表/n");

     printf("4.在有向图的邻接表基础上计算个顶点的读,并输出/n");

     printf("5,以有向图的邻接表为基础输出它的拓扑排序序列/n");

     printf("6,采用邻接矩阵存储一个有向图,输出但源点到其它个点的最短路径/n");

     printf("7,采用邻接表存储实现无向图的深度优先搜索/n");

     printf("8,采用该邻接表存储实现无向图的广度优先搜索遍历/n");

     printf("9,采用邻接矩阵存储实现无向图的最小生成树的PRIM 算法/n");

     printf("0,退出/n");

     printf("请输入你的选择/n");

     scanf("%d",&select);

     switch(select){

     case 1: creatLink(&G1);

         printf("邻接表创建成功/n");

         break;

     case 2: visit(G1);

         break;

     case 3: CreateUDG(G);

         visit_OL(G);

         break;

     case 4:cacu(&G1);

         printdegree(G1);

         break;

     case 5: if(!TopologiSort(G1))printf("Toposort is not success!/n");

         break;

     case 6: CreateUDN(G2);

             PrintfMGraph(G2);

             printf("请输入但源点v0/n");

             scanf("%s",&v0);

             ShortestPath_DIJ(G2,v0,P,D);

         break;

     case 7: DFSTraverse(G1,Vvisit);

         break;

     case 8: BFSTraverse(G1,Vvisit);

         break;

     case 9: MiniSpanTree_PRIM(G2,v0);

         break;

     case 0:

         break;

     }

}

}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值