无向网的最小生成树(Kruskal算法)

最小生成树的Kruskal算法,适用于边较少的连通网,下面的算法中没有将其像上一篇日志一样转换为一棵树,要转换的话就像上一篇日志一样,进行建树就可以了,下面是代码

"graph.h"文件

#include<iostream> #include<queue> #include<string> using namespace std; const int MAX_VERTEX_NUM=20; bool visited[20];//用于遍历时辅组使用 class VNode; //表结点 class ArcNode { public: int adjvex; int weight; ArcNode *nextarc; friend class VNode; }; class ALGraph; //头结点 class VNode { string data; ArcNode *firstarc; friend class ALGraph; }; class EDGE { public: int begin; int end; int cost; friend class ALGraph; }; EDGE edges[20]; //设为全局变量,便于将初始化和使用分开 class ALGraph { private: VNode vertices[MAX_VERTEX_NUM]; int vexnum; int arcnum; public: void CreateUDG_ALG() { //采用邻接表构造无向网G //创建邻接表的过程顺便将信息存入edges中,便于后面的求最小生成树 string v1,v2; int i,j,k,w; cout<<"输入顶点数和边数:"; cin>>vexnum>>arcnum; cout<<"输入顶点民称:"; for(i=0;i<vexnum;i++) { cin>>vertices[i].data; vertices[i].firstarc=NULL; } //输入各弧并构造邻接表 for(k=0;k<arcnum;k++) { cout<<"输入边所对应的两个顶点和该边的权值:"; cin>>v1>>v2>>w; i=Locate_Vex(v1); j=Locate_Vex(v2); while(i<0|| i>vexnum-1 || j<0 || j>vexnum-1) { cout<<"结点位置输入错误,重新输入: "; cin>>v1>>v2>>w; i=Locate_Vex(v1); j=Locate_Vex(v2); } ArcNode *p=new ArcNode; p->adjvex=j; p->weight=w; p->nextarc=vertices[i].firstarc; vertices[i].firstarc=p; ArcNode *q=new ArcNode; q->adjvex=i; q->weight=w; q->nextarc=vertices[j].firstarc; vertices[j].firstarc=q; edges[k].begin=i; edges[k].end=j; edges[k].cost=w; } } int Locate_Vex(string v) //返回顶点在数组中的位置 { for(int k=0;vertices[k].data!=v;k++); return k; } void BFS_Traverse() //广度优先遍历 { int i,k,w; queue<int> q; ArcNode *p; for(i=0;i<vexnum;i++) visited[i]=false; for(i=0;i<vexnum;i++) { if(!visited[i]) { visited[i]=true; cout<<vertices[i].data<<" "; if(vertices[i].firstarc) q.push(i); while(!q.empty()) { k=q.front(); q.pop(); for(p=vertices[k].firstarc;p;p=p->nextarc) { w=p->adjvex; if(!visited[w]) { visited[w]=true; cout<<vertices[w].data<<" "; if(vertices[w].firstarc) q.push(w); } } } } } } //深度优先遍历 void DFS_Traverse() { for(int i=0;i<vexnum;i++) visited[i]=false; for(i=0;i<vexnum;i++) if(!visited[i]) DFS(i); } void DFS(int i) { visited[i]=true; cout<<vertices[i].data<<" "; ArcNode *p; for(p=vertices[i].firstarc;p;p=p->nextarc) { int w=p->adjvex; if(!visited[w]) DFS(w); } } /*Kruskal算法*/ /*------------------------------------------------ /假设N=(V,{VR})是一个连通网,令最小生成树初始状态为 /只有n个顶点的非连通图,T=(V,{}),图中的每个顶点自成 /一个连通分量.在VR中选择权值最小边,若该边依附的顶点 /落在T的不同连通分量上,则将此边加入T中,然后合并两个 /连通分量,否则就舍弃那条边,直至T中所有顶点都在同 /一连通分量上为止。 /-------------------------------------------------- /为了判断所选的边加入到生成树中是否会形成回路,可以 /将各个顶点划分为所属集合的方法来解决,每个集合中的顶点 /表示一个无回路的连通分量.用parents[]表示这些顶点,初始 /值为0,表示各顶点自成一个连通分量.从edges中依次序选择 /一条边时,查找它的两个顶点所属的分量的bnf和edf. /当bnf和edf不同时,就说明该边的两个顶点属于两个不同 /集合,相等时说明在同一个集合。 /------------------------------------------------*/ void Kruskal_Min_Tree() { int bnf,edf; int parents[20]; Sort(edges); //按照权值大小排序 for(int i=0;i<vexnum;i++) //初始化parent[]数组 parents[i]=0; for(i=0;i<arcnum;i++) { bnf=Find(parents,edges[i].begin); edf=Find(parents,edges[i].end); if(bnf!=edf) { parents[bnf]=edf; cout<<"("<<vertices[edges[i].begin].data<<','<<vertices[edges[i].end].data<<','<<edges[i].cost<<')'<<endl; } } } void Sort(EDGE edges[]) { for(int i=0;i<arcnum;i++) for(int j=i+1;j<arcnum;j++) if(edges[i].cost>edges[j].cost) { EDGE temp; temp.begin=edges[i].begin; temp.end=edges[i].end; temp.cost=edges[i].cost; edges[i].begin=edges[j].begin; edges[i].end=edges[j].end; edges[i].cost=edges[j].cost; edges[j].begin=temp.begin; edges[j].end=temp.end; edges[j].cost=temp.cost; } } int Find(int parents[],int f) { while(parents[f]>0) f=parents[f]; return f; } };


测试函数"main.cpp"

#include"graph.h" int main() { ALGraph G; G.CreateUDG_ALG(); cout<<"图的广度优先遍历为:"; G.BFS_Traverse(); cout<<endl; cout<<"图的深度优先遍历为:"; G.DFS_Traverse(); cout<<endl; cout<<"最小生成树的边的组成和对应的权值为:"<<endl; G.Kruskal_Min_Tree(); cout<<endl; return 0; }

输出结果:

输入顶点数和边数:9 15 输入顶点民称:v1 v2 v3 v4 v5 v6 v7 v8 v9 输入边所对应的两个顶点和该边的权值:v1 v6 7 输入边所对应的两个顶点和该边的权值:v1 v7 3 输入边所对应的两个顶点和该边的权值:v1 v2 2 输入边所对应的两个顶点和该边的权值:v2 v7 6 输入边所对应的两个顶点和该边的权值:v2 v3 4 输入边所对应的两个顶点和该边的权值:v6 v5 6 输入边所对应的两个顶点和该边的权值:v6 v9 5 输入边所对应的两个顶点和该边的权值:v7 v9 1 输入边所对应的两个顶点和该边的权值:v7 v8 3 输入边所对应的两个顶点和该边的权值:v3 v8 2 输入边所对应的两个顶点和该边的权值:v3 v4 2 输入边所对应的两个顶点和该边的权值:v9 v5 2 输入边所对应的两个顶点和该边的权值:v9 v8 4 输入边所对应的两个顶点和该边的权值:v8 v4 8 输入边所对应的两个顶点和该边的权值:v5 v4 1 图的广度优先遍历为:v1 v2 v7 v6 v3 v8 v9 v5 v4 图的深度优先遍历为:v1 v2 v3 v4 v5 v9 v8 v7 v6 最小生成树的边的组成和对应的权值为: (v7,v9,1) (v5,v4,1) (v3,v8,2) (v3,v4,2) (v9,v5,2) (v1,v2,2) (v1,v7,3) (v6,v9,5) Press any key to continue

生产的无向网和生成树的图和上一篇日志的一样,所以要看图的话 就在上一篇,这里就不重复给出了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值