kruskal算法实现最小生成树

xiaoxiao2021-02-27  364

之前写了prim算法实现最小生成树,接下来看看kruskal算法 对于给定的图G,令其最小生成树T初始时为G到n个顶点(边为0),然后将G的边上权重从小到大排序,每次选取最小到边,如果选中的边的两个顶点是连通的,则删除该条边,选取下一条边,如果选中的两个顶点不连通,那么该边加入到T中,如此重复,直到所有顶点都连通 看图:

好了,接下来就是画思想为实践了,不妨先定义一个定位权重的函数

//根据权重定位边的两个顶点,值得注意可能有多条边权重相同 void adjaMultiList::locateInfo(double weight, vector<int> &a, vector<int> &b) { for (int i = 0; i < iVertex; ++i) { edgeNode*p = verNode[i].firstEdge; while (p) { if (p->info == weight) { a.push_back(p->aVertex); b.push_back(p->bVertex); } p = p->aLink; } } } void adjaMultiList::kruskalTree() { cout << "最小生成树的各边及权值为:" << endl; /* kruskal算法关键问题是如何判断在选中若干条边后,某两个顶点是否连通,可以根据书上的一种简单的 方法,定义一个一维数组f,开始时每个顶点为一个连通分量,f[i]=i;比如加入边a,b后,可以令f[a]=a[b] 那么以后判断时就可以根据f[a]和f[b]是否相等即可 */ int f[MAXVERTEX]; int u[MAXVERTEX];//u用来保存图的最小生成树的顶点 for (int i = 0; i < iVertex; ++i)//初始时为空 { u[i] = -1; f[i] = i; } int m = 0;//m保存u中顶点个数 int n = 0;//n表示已经选中的边数 vector<double> dEdge;//保存所有边 for (int i = 0;i < iVertex;++i) { edgeNode*p = verNode[i].firstEdge; while (p) { dEdge.push_back(p->info); p = p->aLink; } } sort(dEdge.begin(), dEdge.end());//排序 while(n!=iVertex-1)//如果边数为顶点数-1,则整个图连通 { vector<int> aVec; vector<int> bVec; double weight = *dEdge.begin(); locateInfo(weight, aVec, bVec); for (int i = 0; i < aVec.size(); ++i) { int a = aVec[i]; int b = bVec[i]; if (m == 0)//当u中没有顶点时,肯定可以连,并且增加两个顶点 { cout << "边: " << a<< " " << b << " 权重: " << *dEdge.begin() << endl; m += 2; u[0] = a; u[1] = b; f[a] = f[b]; auto p = dEdge.begin(); dEdge.erase(p); ++n; //continue; } else { int countA = 0; int countB = 0; for (int j = 0; j < m; j++) { if (u[j] == a) ++countA; if (u[j] == b) ++countB; } if (countA&&countB)//如果两个都在u中 { //两个顶点都在u中,且是连通的,那么不能连 if (f[a] == f[b]) { auto p = dEdge.begin(); dEdge.erase(p); } else { cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl; auto p = dEdge.begin(); dEdge.erase(p); ++n; //这里要注意,将a以及所有与a连通的顶点的f[]值都改为b的,或者反过来 for (int i1 = 0; i1 < iVertex; i1++) { if (f[i1] == f[a]) f[i1] = f[b]; } } continue; } if (!countA && !countB)//两个顶点均不在u中 { m += 2; u[m - 2] = a; u[m - 1] = b; f[a] = f[b]; cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl; auto p = dEdge.begin(); dEdge.erase(p); ++n; continue; } if (countA + countB == 1)//有一个结点在u中 { cout << "边: " << a << " " << b << " 权重: " << *dEdge.begin() << endl; ++m; if (countA) { u[m - 1] = b; //b不在u中,直接f[b]=f[a]即可 f[b] = f[a]; } else { u[m - 1] = a; //相反 f[a] = f[b]; } auto p = dEdge.begin(); dEdge.erase(p); ++n; continue; } } } } }

转载请注明原文地址: https://www.6miu.com/read-2991.html

最新回复(0)