1. 邻接矩阵存储 //图的邻接矩阵存储表示 #define INFINITY INT_MAX #define MAX_VERTEX_NUM 20 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网} typedef enum {OK, ERROR} Status; typedef struct ArcCell{ int adj; //顶点关系类型。对于无权图,用0或1表示相邻否。对于有权图,则为权值类型。 string info; //该弧所携带的信息 }ArcCell, AdjMatrix; typedef struct { int vexs[MAX_VERTEX_NUM]; //顶点向量 AdjMatrix arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵 int vexnum, arcnum; //图的当前顶点数和弧数 GraphKind kind; //图的种类标志 }MGraph; bool visited[MAX_VERTEX_NUM]; //设访问标志数组,供遍历时使用 int parent[MAX_VERTEX_NUM]; //Kruskal算法-记录所有边的端点和权值的结构定义 typedef struct { int begin; //边的始端 int end; //边的终端 int weight; //边的权值 int tag; //边已被选择0或未被选择1 }Edge; 2. kruskal算法 void MiniSpanTree_Kruskal(MGraph G) { //用克鲁斯卡尔Kruskal算法构造最小生成树 //逐步从剩余边中,选择权值最小的边放入最小生成树中,前提是不能造成连通网 //Edge结构用于记录各个边的始端、末端和权值和是否已被选择的标志位(1被选择,0未被选择) // struct { // int begin; // int end; // int weight; // int tag; // }Edge; //int parent[MAX_VERTEX_NUM]; //存储某顶点的父顶点,初始化为-1,即不存在 int i,j,k,m; k=1; Edge edges[MAX_VERTEX_NUM+1]; //0号单元作排序时暂存用 //从1开始存储各个边 for(i=0; i<G.vexnum; ++i) for(j=i+1; j<G.vexnum; ++j) if(G.arcs[i][j].adj < INT_MAX) { edges[k].begin = i; edges[k].end = j; edges[k].weight = G.arcs[i][j].adj; edges[k].tag = 0; k++; }; //对各边按权值从小到大进行排序 for(i=1; i<=G.arcnum-1; ++i) for(j=G.arcnum; j>i; --j) if(edges[j].weight < edges[j-1].weight) { edges[0] = edges[j]; edges[j] = edges[j-1]; edges[j-1] = edges[0]; }; for(i=1; i<=G.arcnum-1; ++i) cout<<edges[i].begin<<"--"<<edges[i].end<<"="<<edges[i].weight<<endl; //m表示最小生成树中的边数,k表示即将访问的边的序号 k=1; m=0; //m用于计算已经已经得到的最小生成数的边数 while(m<G.vexnum-1 && k<=G.arcnum) { //当最小生成树边数不够n-1时,且还有边未访问过时,继续构造最小生成树,n为顶点数 //从剩余边中选择一个权值最小的边,由于edges已经排序过,目前最小的边即第k个边 //判断该边加入最小生成树后,是否会形成环 if(IsConnected(G, edges, k)==OK){ //如果不会形成环路,则输出该边,并置标志位为1 edges[k].tag = 1; cout<<edges[k].begin<<"----"<<edges[k].end<<"="<<edges[k].weight<<endl; m++; }else{ //如果会形成环路,放弃次边 } k++; //加1,指向下一个要被访问的边 }; if(m<G.vexnum-1) cout<<"生成最小生成树失败!该网非连通!"<<endl; }//Kruskal Status IsConnected(MGraph G, Edge edges[], int k) { //判断某网是否存在环 MGraph GTest=G; Status test = OK; int i,j; for(i=0; i<G.vexnum; ++i) //初始化 parent[i] = -1; for(i=0; i<GTest.vexnum; ++i) for(j=0; j<GTest.vexnum; ++j) GTest.arcs[i][j].adj = INT_MAX; for(i=1; i<k; ++i) if(edges[i].tag ==1) GTest.arcs[edges[i].begin][edges[i].end].adj = GTest.arcs[edges[i].end][edges[i].begin].adj = edges[i].weight; GTest.arcs[edges[k].begin][edges[k].end].adj = GTest.arcs[edges[k].end][edges[k].begin].adj = edges[k].weight; //判断网G是否存在环,用深度优先排序 int v; for(v=0; v<GTest.vexnum; ++v) //访问标志数组初始化 visited[v] = false; for(v=0; v<GTest.vexnum; ++v) if(!visited[v]) //对未访问的顶点调用DFS if(test == OK) test = IsCircle(GTest, v); else break; return test; } Status IsCircle(MGraph G, int v) { //从第v个顶点出发,递归地深度优先遍历图G int w; visited[v] = true; for(w = FirstAdjVex(G,v); w>=0; w=NextAdjVex(G, v, w)) if(!visited[w]) { parent[w] = v; IsCircle(G, w); //对v的尚未访问的邻接顶点w递归调用DFS }else if(parent[v] != w) { //如果某顶点访问过,且不是v的直接父节点,说明存在环 return ERROR; } return OK; } 3. 构造测试用的有向网 void CreateUDNTest(MGraph &G) { //构造一个测试用的无向网 int i,j; //数组a[10][3]存放“边”和对应的权值 int a[10][3] = { {0, 1, 6}, {0, 2, 1}, {0, 3, 5}, {1, 2, 5}, {1, 4, 3}, {2, 3, 5}, {2, 4, 6}, {2, 5, 4}, {4, 5, 6}, {3, 5, 2} }; G.kind = UDN; G.vexnum = 6; G.arcnum = 10; for(i=0; i<G.vexnum; ++i) //构造顶点向量 G.vexs[i] = i; for(i=0; i<G.vexnum; ++i) //初始化为全INT_MAX for(j=0; j<G.vexnum; ++j) { G.arcs[i][j].adj = INT_MAX; G.arcs[i][j].info = ""; } for(i=0; i<G.arcnum; ++i) //对存在的边赋值 G.arcs[a[i][0]][a[i][1]].adj = G.arcs[a[i][1]][a[i][0]].adj = a[i][2]; } 4. 主函数 int main() { MGraph gra2; CreateUDNTest(gra2); //构造无向网G cout<<"构造最小生成树:"<<endl; MiniSpanTree_Kruskal(gra2); return 0; }