图的存储、遍历和求最小生成树

来源:互联网 发布:程序员的成长之路 编辑:程序博客网 时间:2024/06/10 02:03
/*图的存储及遍历*/  #include<iostream>  using namespace std;  //-----------------------------------  //邻接矩阵的存储及深度和广度遍历  //-----------------------------------     /*邻接矩阵的类型定义*/  #define MAX 10000000  #define MAX_VERTEX_NUM 20  typedef enum{ DG,DN,UDG,UDN }GraphKind;//有向图,有向网,无向图,无向网  typedef struct  {         char vexs[MAX_VERTEX_NUM];//用一维数组存储顶点信息         int edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//用二维数组充当矩阵,来存储顶点边的信息         int vexnum,edgenum;//顶点树和边数         GraphKind kind;//图的种类  }MGraph;     /*构造无向图的邻接矩阵*/  void CreateUDG_AM(MGraph &G,int n,int e)  {         G.vexnum=n;         G.edgenum=e;                 int i,j,k;         for(i=0;i<n;i++)                cin>>G.vexs[i];//输入顶点信息            for(i=0;i<n;i++)                for(j=0;j<n;j++)                       G.edges[i][j]=0;//将矩阵初始化为0            for(k=0;k<e;k++)         {                cin>>i>>j;//这里只用输入对称的边就行,也就是输入下矩阵或是上矩阵                G.edges[i][j]=G.edges[j][i]=1;//输入边的信息         }  }     /****************************无向图的深度优先遍历************************/  int visited[MAX_VERTEX_NUM];     void DF_AM(MGraph &G,int i)  {         int j;         cout<<G.vexs[i]<<" ";         visited[i]=1;         for(j=0;j<G.vexnum;j++)         {                if((G.edges[i][j])==1&&(visited[j])==0)                       DF_AM(G,j);         }  }     void DF_Traverse_AM(MGraph &G)  {         int i;         for(i=0;i<G.vexnum;i++)         {                visited[i]=0;         }         for(i=0;i<G.vexnum;i++)         {                if(!visited[i])                       DF_AM(G,i);         }  }     /*********************无向图的广度优先遍历*****************************/     //循环队列的类型定义  const int Queue_Size=100;     typedef struct circlQueue  {         int *elem;         int rear;         int front;         int queueSize;  }circlQueue;     //初始化  void initQueue_C(circlQueue &Q)  {         Q.elem=new int[Queue_Size];         Q.front=Q.rear=0;//首尾指针相等说明队列为空。         Q.queueSize=Queue_Size;  }     //入队列  void enterQueue_C(circlQueue &Q,int x)  {         if(((Q.rear+1)%Q.queueSize)==Q.front)//判断栈满的情况                cout<<"Queue OverFlow!";         Q.elem[Q.rear]=x;         Q.rear=(Q.rear+1)%Queue_Size;//尾指针应以此种方式加1,才会实现循环队列。  }     //出队列  char outputQueue_C(circlQueue &Q)  {         int e;         if(Q.rear==Q.front)                cout<<"Queue Empty";         e=Q.elem[Q.front];         Q.front=(Q.front+1)%Q.queueSize;;//头指针应以此种方式加1,才会实现循环队列。         return e;  }  //广度遍历  void BF_Traverse_AM(MGraph &G)  {         int i,j,v;         for(i=0;i<G.vexnum;i++)                visited[i]=0;         circlQueue Q;         initQueue_C(Q);//队列实现了“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问         for(i=0;i<G.vexnum;i++)         {                if(!visited[i])                {                       cout<<G.vexs[i]<<" ";                       visited[i]=1;                       enterQueue_C(Q,i);                       while(Q.front!=Q.rear)                       {//这个循环是将队列里面的顶点取出来,然后进行下面的for循环                              v=outputQueue_C(Q);                              for(j=0;j<G.vexnum;j++)                              {//这个循环是将顶点的全部邻接点依次访问并且入队列                                     if(G.edges[v][j]&&(!visited[j]))                                     {                                            cout<<G.vexs[j]<<" ";                                            visited[j]=1;                                            enterQueue_C(Q,j);                                     }                              }                       }                }         }  }     //-----------------------------------------------  //邻接表的存储及深度和广度遍历  //-----------------------------------------------  typedef struct EdgeNode  {//边表结点的定义         int adjvex;//存放邻接点在顶点表中的位置         struct EdgeNode * nextedge;//指向下一个边表结点         int weight;  }EdgeNode;     typedef struct VexNode  {//顶点表结点的定义         char vex;//存放顶点信息         EdgeNode * firstedge;//指向第一个边表结点  }VexNode;     typedef struct  {//顶点表的定义           VexNode vexs[MAX_VERTEX_NUM];         int vexnum,edgenum;         GraphKind kind;  }LGraph;     /*构造有向图的邻接表*/  void CreateDG_AL(LGraph &G,int n,int e)  {         int i,j,k;         G.vexnum=n;         G.edgenum=e;         G.kind=DG;         for(i=0;i<n;i++)         {                cin>>G.vexs[i].vex;                G.vexs[i].firstedge=NULL;//初始化为空         }         for(k=0;k<e;k++)         {                EdgeNode *p;                cin>>i>>j;                p=new EdgeNode;                p->adjvex=j;                p->nextedge=G.vexs[i].firstedge;                G.vexs[i].firstedge=p;//采用头插法         }  }     /*********************有向图的深度优先遍历**************************/  void DF_AL(LGraph &G,int v)  {         int j;         EdgeNode *p;         cout<<G.vexs[v].vex<<" ";         visited[v]=1;         for(p=G.vexs[v].firstedge;p;p=p->nextedge)         {                j=p->adjvex;                if(!visited[j])                       DF_AL(G,j);         }  }     void DF_Traverse_AL(LGraph &G)  {         int i;         for(i=0;i<G.vexnum;i++)         {                visited[i]=0;         }         for(i=0;i<G.vexnum;i++)         {                if(!visited[i])                       DF_AL(G,i);         }  }  /* 何问起 hovertree.com *//*********************有向图的广度优先遍历**************************/  void BF_Traverse_AL(LGraph &G)  {         int i,j,v;         EdgeNode *p;         for(i=0;i<G.vexnum;i++)                visited[i]=0;         circlQueue Q;         initQueue_C(Q);//队列实现了“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问         for(i=0;i<G.vexnum;i++)         {                if(!visited[i])                {                       cout<<G.vexs[i].vex<<" ";                       visited[i]=1;                       enterQueue_C(Q,i);                       while(Q.front!=Q.rear)                       {//这个循环是将队列里面的顶点取出来,然后进行下面的for循环                              v=outputQueue_C(Q);                              for(p=G.vexs[v].firstedge;p;p=p->nextedge)                              {//这个循环是将顶点的全部邻接点依次访问并且入队列                                     j=p->adjvex;                                     if(!visited[j])                                     {                                            cout<<G.vexs[j].vex<<" ";                                            visited[j]=1;                                            enterQueue_C(Q,j);                                     }                              }                       }                }         }  }  void main()  {         /*MGraph G;        CreateUDG_AM(G,6,6);        DF_Traverse_AM(G);        cout<<endl;        BF_Traverse_AM(G);*/            LGraph G;         CreateDG_AL(G,5,7);         DF_Traverse_AL(G);         cout<<endl;         BF_Traverse_AL(G);  }
/* Prim算法生成最小生成树 */void MiniSpanTree_Prim(MGraph G){cout<<"Prim算法生成最小生成树,结果为:"<<endl;int min,i,j,k;int adjvex[MAXVEX];int lowcost[MAXVEX];lowcost[0]=0;adjvex[0]=0;for(i=1;i<G.numVertexes;i++){lowcost[i]=G.arc[0][i];adjvex[i]=0;}for(i=1;i<G.numVertexes;i++){min=INFINITY;j=1;k=0;while(j<G.numVertexes){if(lowcost[j]!=0 && lowcost[j]<min){min=lowcost[j];k=j;}j++;}cout<<"("<<adjvex[k]<<","<<k<<")"<<endl;lowcost[k]=0;for(j=1;j<G.numVertexes;j++){if(lowcost[j]!=0 && G.arc[k][j]<lowcost[j]){lowcost[j]=G.arc[k][j];adjvex[j]=k;}}}cout<<endl;}/* Kruskal 算法生成最小生成树 */class Edge{/*对边集数组Edge结构的定义*/public:int begin;int end;int weight;};void Swap(Edge *edges,int i,int j)/* 交换权值 以及头和尾 */{int temp;temp=edges[i].begin;edges[i].begin=edges[j].begin;edges[j].begin=temp;temp=edges[i].end;edges[i].end=edges[j].end;edges[j].end=temp;temp=edges[i].weight;edges[i].weight=edges[j].weight;edges[j].weight=temp;}void sort(Edge edges[],MGraph *G)/* 对权值进行排序 */{int i,j;for ( i=0;i<G->numEdges;i++){for ( j=i+1;j<G->numEdges;j++){if (edges[i].weight>edges[j].weight){Swap(edges,i,j);}}}cout<<"权排序之后的为:"<<endl;for (i=0;i<G->numEdges;i++){cout<<"("<<edges[i].begin<<","<<edges[i].end<<")"<<endl;}}int Find(int *parent,int f)/*查找连线顶点的尾部下标*/{while (parent[f]>0)f=parent[f];return f;}void MiniSpanTree_Kruskal(MGraph G){int i,j,n,m;Edge edges[MAXEDGE];int parent[MAXVEX];/*将邻接数组G转化为边集数组edges并按权由小到大排序*******BEGIN*********/int k=0;for ( i=0;i<G.numVertexes-1;i++){for (j=i+1;j<G.numVertexes;j++){if (G.arc[i][j]<INFINITY){edges[k].begin=i;edges[k].end =j;edges[k].weight=G.arc[i][j];k++;}}}sort(edges, &G);/***************END***********************/for (i=0;i<G.numVertexes;i++)parent[i]=0;/* 初始化数组值为0 */cout<<"Kruskal 算法生成最小生成树,结果为:"<<endl;for (i=0;i<G.numEdges;i++)/* 循环每一条边 */{n=Find(parent,edges[i].begin);m=Find(parent,edges[i].end);if (n!=m) /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */{parent[n]=m;/* 将此边的结尾顶点放入下标为起点的parent中。 *//* 表示此顶点已经在生成树集合中 */cout<<"("<<edges[i].begin<<","<<edges[i].end<<") "<<edges[i].weight<<endl;}}}

对于如下所示的图:


运行程序,结果如下:



阅读全文
0 0