图__最小生成树
分类:
//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------
/*
A
/ | \
B -- F -- E
\ / \ /
C -- D
A B C D E F
索引: 0 1 2 3 4 5
权值:A-B 6 A-F 1 A-E 5
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 9
//无向图
A B C D E
A 0 1 1 0 0
B 1 0 0 1 1
C 1 0 0 0 0
D 0 1 0 0 0
E 0 1 0 0 0
*/
Node.h
Node.cpp
Edge.h
Edge.cpp
CMap.h
CMap.cpp
demo.cpp
本文章已收录于:
![](http://static.blog.csdn.net/images/category_icon.jpg)
作者同类文章
X
版权声明:本文为博主原创文章,未经博主允许不得转载。
图---最小生成树
学习总结:
//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------
/*
A
/ | \
B -- F -- E
\ / \ /
C -- D
A B C D E F
索引: 0 1 2 3 4 5
权值:A-B 6 A-F 1 A-E 5
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 9
//无向图
A B C D E
A 0 1 1 0 0
B 1 0 0 1 1
C 1 0 0 0 0
D 0 1 0 0 0
E 0 1 0 0 0
*/
Node.h
#ifndef NODE_H
#define NODE_H
//-----------------
//-----顶点----------
class Node{
public:
Node(char data = 0);
char m_cData;
bool m_bIsVisited;
};
#endif
Node.cpp
#include"Node.h"
#include<iostream>
#include<stdio.h>
using namespace std;
Node::Node(char data){
m_cData = data;
m_bIsVisited = false;
}
Edge.h
#ifndef EDGE_H
#define EDGE_H
//-------------------
//----边-------------
class Edge{
public:
Edge(int nodeIndexA = 0, int nodeIndexB = 0, int weightValue = 0);
public:
int m_iNodeIndexA;//A索引
int m_iNodeIndexB;//B索引
int m_iWeightValue;//权值
bool m_bSelected;
};
#endif
Edge.cpp
#include"Edge.h"
Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue){
m_iNodeIndexA = nodeIndexA;
m_iNodeIndexB = nodeIndexB;
m_iWeightValue = weightValue;
m_bSelected = false;
}
CMap.h
#ifndef CMAP_H
#define CMAP_H
#include"Node.h"
#include"Edge.h"
#include<iostream>
#include<vector>
using namespace std;
//---------------------------
//--------图--------------------
class CMap{
public:
CMap(int capacity);
~CMap();
bool addNode(Node *pNode);//添加顶点(节点)
void resetNode(); //重置顶点
bool setValueToMatrixForDirectedGraph(int row, int col, int val = 1);//为有向图设置邻接矩阵
bool setValueToMatrixForUndriectedGraph(int row, int col, int val = 1);//为无向图设置邻接矩阵
void printMatrix();//打印邻接矩阵
void depthFirstTraverse(int nodeIndex);//深度优先遍历
void breadthFirstTraverse(int nodeIndex);//广度优先遍历
void primTree(int nodeIndex);//普里姆算法最小生成树
void kruskalTree(); //克鲁斯卡尔算法最小生成树
private:
bool getValueFromMatrix(int row, int col, int &val);//从矩阵中获取权值
void breadthFirstTraverseImpl(vector<int> preVec);//广度优先遍历实现函数
int getMinEdge(vector<Edge> edgeVec);//获得最小边
bool isInSet(vector<int> nodeSet, int target);//判断顶点(节点)是否在集合中
void mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB);//合并两个点的集合,B合并到A中
private:
int m_iCapacity;//容量
int m_iNodeCount;//节点个数
Node *m_pNodeArray;//顶点数组
int *m_pMatrix;//存放邻接矩阵,弧
Edge *m_pEdge;//边的集合
};
#endif
CMap.cpp
#include"CMap.h"
CMap::CMap(int capacity){
m_iCapacity = capacity;
m_iNodeCount = 0;
m_pNodeArray = new Node[m_iCapacity];
m_pMatrix = new int[m_iCapacity*m_iCapacity];
//memset(m_pMatrix, 0, m_iCapacity*m_iCapacity*sizeof(int));//内存的设定
//或
for(int i = 0; i < m_iCapacity*m_iCapacity; i++){
m_pMatrix[i] = 0;
}
m_pEdge = new Edge[m_iCapacity-1];//边的集合
}
CMap::~CMap(){
delete []m_pNodeArray;
delete []m_pMatrix;
delete []m_pEdge;
}
bool CMap::addNode(Node *pNode){
if(pNode == NULL){
return false;
}
m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
m_iNodeCount++;
return true;
}
void CMap::resetNode(){
for(int i = 0; i < m_iNodeCount; i++){
m_pNodeArray[i].m_bIsVisited = false;
}
}
bool CMap::setValueToMatrixForDirectedGraph(int row, int col, int val){
if(row < 0 || row >= m_iCapacity){
return false;
}
if(col < 0 || col >= m_iCapacity){
return false;
}
m_pMatrix[row*m_iCapacity + col] = val;
return true;
}
bool CMap::setValueToMatrixForUndriectedGraph(int row, int col, int val){
if(row < 0 || row >= m_iCapacity){
return false;
}
if(col < 0 || col >= m_iCapacity){
return false;
}
m_pMatrix[row*m_iCapacity + col] = val;
m_pMatrix[col*m_iCapacity + row] = val;
return true;
}
void CMap::printMatrix(){
for(int i = 0; i < m_iCapacity; i++){
for(int j = 0; j < m_iCapacity; j++){
cout << m_pMatrix[i*m_iCapacity + j] << " ";
}
cout << endl;
}
}
void CMap::depthFirstTraverse(int nodeIndex){//深度优先搜索
int value = 0;
cout << m_pNodeArray[nodeIndex].m_cData << " ";
m_pNodeArray[nodeIndex].m_bIsVisited = true;
//通过邻接矩阵判断是否与其他的顶点有连接,看是否存在一条连通的弧
for(int i = 0; i < m_iCapacity; i++){
getValueFromMatrix(nodeIndex, i, value);//取出相应的弧
//判断有弧连接其他顶点
if(value != 0){//有这样的弧
//判断 连接的顶点 是否被访问过
if(m_pNodeArray[i].m_bIsVisited){
continue;
}
else{//没有访问过,则递归访问
depthFirstTraverse(i);
}
}
else{
continue;
}
}
}
void CMap::breadthFirstTraverse(int nodeIndex){//广度优先遍历
cout << m_pNodeArray[nodeIndex].m_cData << " ";
m_pNodeArray[nodeIndex].m_bIsVisited = true;
vector<int> cur;
cur.push_back(nodeIndex);//保存顶点的索引
breadthFirstTraverseImpl(cur);//实现广度优先遍历的函数
}
//普里姆算法最小生成树
void CMap::primTree(int nodeIndex){
int value = 0;//保存权值
int edgeCount = 0;//边的计数器
vector<int> nodeVec;//存储点的集合,用索引代替
vector<Edge> edgeVec;//边的集合
cout << m_pNodeArray[nodeIndex].m_cData << endl;
nodeVec.push_back(nodeIndex);
m_pNodeArray[nodeIndex].m_bIsVisited = true;
while(edgeCount < m_iCapacity - 1){
int temp = nodeVec.back();
//放入待选边的集合
for(int i = 0; i < m_iCapacity; i++){
//寻找待选边的集合
getValueFromMatrix(temp, i, value);//从邻接矩阵中获取权值
if(value != 0){
if(m_pNodeArray[i].m_bIsVisited){
continue;
}
else{
Edge edge(temp, i, value);//确定了nodeIndexA,nodeIndexB等索引
edgeVec.push_back(edge);//不会放重复的边
}
}
}
//从待选边中选出最小的边
int edgeIndex = getMinEdge(edgeVec);//返回最小边的索引
edgeVec[edgeIndex].m_bSelected = true;
cout << edgeVec[edgeIndex].m_iNodeIndexA << "-->" << edgeVec[edgeIndex].m_iNodeIndexB << " ";
cout << edgeVec[edgeIndex].m_iWeightValue << endl;
//放入最小生成树边的集合中
m_pEdge[edgeCount] = edgeVec[edgeIndex];
edgeCount++;
//最小边连接的点
int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;
//将下一个点放入点的集合
nodeVec.push_back(nextNodeIndex);
m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
cout << m_pNodeArray[nextNodeIndex].m_cData << endl;
}
}
//克鲁斯卡尔算法最小生成树
void CMap::kruskalTree(){
int value = 0;//存放权值
int edgeCount = 0;//边计数器
//定义存放节点 集合 的数组,可能不止一个点的集合,demo.cpp运行结果就是如此
vector<vector<int> > nodeSets;
//<1>取出所有边
vector<Edge> edgeVec;
for(int i = 0; i < m_iCapacity; i++){
for(int j = i + 1; j < m_iCapacity; j++){//上三角,不包含主对角线,例如A-A,B-B..没意义
getValueFromMatrix(i, j, value);//从邻接矩阵中获取权值
if(value != 0){
Edge edge(i, j, value);//确定了nodeIndexA,nodeIndexB等索引
edgeVec.push_back(edge);//放入边集合中
}
}
}
//<2>从所有边中取出组成最小生成树的边
//1.算法结束条件
while(edgeCount < m_iCapacity - 1){
//2.从边集合中找到最小边
int minEdgeIndex = getMinEdge(edgeVec);
edgeVec[minEdgeIndex].m_bSelected = true;
//3.找出最小边连接的点
int nodeIndexA = edgeVec[minEdgeIndex].m_iNodeIndexA;
int nodeIndexB = edgeVec[minEdgeIndex].m_iNodeIndexB;
//4.找出点所在的集合
bool nodeAIsInSet = false;
bool nodeBIsInSet = false;
int nodeAInSetLabel = -1;
int nodeBInSetLabel = -1;
for(int i = 0; i < nodeSets.size(); i++){//A点集合所在的索引
nodeAIsInSet = isInSet(nodeSets[i], nodeIndexA);
if(nodeAIsInSet){
nodeAInSetLabel = i;
}
}
for(int i = 0; i < nodeSets.size(); i++){//B点集合所在的索引
nodeBIsInSet = isInSet(nodeSets[i], nodeIndexB);
if(nodeAIsInSet){
nodeBInSetLabel = i;
}
}
//5.根据点所在集合的不同做不同的处理
if(nodeAInSetLabel == -1 && nodeBInSetLabel == -1){
vector<int> vec;
vec.push_back(nodeAInSetLabel);
vec.push_back(nodeBInSetLabel);
nodeSets.push_back(vec);
}
else if(nodeAInSetLabel == -1 && nodeBInSetLabel != -1){
nodeSets[nodeBInSetLabel].push_back(nodeIndexA);//nodeIndexA到B集合
}
else if(nodeAInSetLabel != -1 && nodeBInSetLabel == -1){
nodeSets[nodeAInSetLabel].push_back(nodeIndexB);//nodeIndexB到A集合
}
//合并两个集合
else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel){
mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);//合并到A集合
for(int k = nodeBInSetLabel; k < (int)nodeSets.size(); k++){
nodeSets[k] = nodeSets[k+1];//清除B集合所占空间
}
}
//两个点在一个集合中形成了回路,舍弃
else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel){
continue;
}
m_pEdge[edgeCount] = edgeVec[minEdgeIndex];//放入边的集合中
edgeCount++;//边数增加
cout << edgeVec[minEdgeIndex].m_iNodeIndexA << "-->" << edgeVec[minEdgeIndex].m_iNodeIndexB << " ";
cout << edgeVec[minEdgeIndex].m_iWeightValue << endl;
}
}
bool CMap::getValueFromMatrix(int row, int col, int &val){
if(row < 0 || row >= m_iCapacity){
return false;
}
if(col < 0 || col >= m_iCapacity){
return false;
}
val = m_pMatrix[row*m_iCapacity + col];
return true;
}
void CMap::breadthFirstTraverseImpl(vector<int> preVec){
int value = 0;
vector<int> cur;
for(int i = 0; i < preVec.size();i++){//上一层的节点数
for(int j = 0; j < m_iCapacity; j++){
//判断当前点与其他点是否有连接
getValueFromMatrix(preVec[i], j, value);//上一个点判断是否有连接j的弧
if(value != 0){
if(m_pNodeArray[j].m_bIsVisited){//看是否被访问过
continue;
}
else{//若没有访问过的话
cout << m_pNodeArray[j].m_cData << " ";//现有的顶点
m_pNodeArray[j].m_bIsVisited = true;
cur.push_back(j);//当前的点保存到数组中
}
}
}
}
if(cur.size() == 0){//下一层节点数的判断
return ;
}
else{//下一层节点数的开始,递归进行深度优先遍历
breadthFirstTraverseImpl(cur);
}
}
int CMap::getMinEdge(vector<Edge> edgeVec){//获得最小边
int minWeight = 0;
int edgeIndex = 0;
int i = 0;
for(; i < edgeVec.size(); i++){//找出第一条没有被访问过的边
if(!edgeVec[i].m_bSelected){
minWeight = edgeVec[i].m_iWeightValue;//权值
edgeIndex = i;//边的索引
break;//找到,则跳出循环
}
}
if(0 == minWeight){//若都被访问过的话
return -1;
}
//接着i后面继续找
for(; i < (int)edgeVec.size(); i++){//找出最小权值的边
if(edgeVec[i].m_bSelected){
continue;
}
else{
if(minWeight > edgeVec[i].m_iWeightValue){
minWeight = edgeVec[i].m_iWeightValue;
edgeIndex = i;
}
}
}
return edgeIndex;
}
bool CMap::isInSet(vector<int> nodeSet, int target){
for(int i = 0; i < nodeSet.size(); i++){
if(nodeSet[i] == target){
return true;
}
}
return false;
}
void CMap::mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB){
for(int i = 0; i < nodeSetB.size(); i++){
nodeSetA.push_back(nodeSetB[i]);
}
}
demo.cpp
#include"CMap.h"
#include<iostream>
using namespace std;
//---------------------------------------
//-----根据下图----------------------------------------
//--实现普里姆算法(Prim)--及--克鲁斯卡尔算法(kruskal)---------------
/*
A
/ | \
B -- F -- E
\ / \ /
C -- D
A B C D E F
索引: 0 1 2 3 4 5
权值: A-B 6 A-F 1 A-E 5
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 9
//无向图
A B C D E
A 0 1 1 0 0
B 1 0 0 1 1
C 1 0 0 0 0
D 0 1 0 0 0
E 0 1 0 0 0
*/
int main(){
Node *node = new Node[6];
node[0].m_cData = 'A';
node[1].m_cData = 'B';
node[2].m_cData = 'C';
node[3].m_cData = 'D';
node[4].m_cData = 'E';
node[5].m_cData = 'F';
CMap *cmap = new CMap(6);
cmap->addNode(&node[0]);
cmap->addNode(&node[1]);
cmap->addNode(&node[2]);
cmap->addNode(&node[3]);
cmap->addNode(&node[4]);
cmap->addNode(&node[5]);
//为无向图设置邻接矩阵
cmap->setValueToMatrixForUndriectedGraph(0, 1, 6);
cmap->setValueToMatrixForUndriectedGraph(0, 4, 5);
cmap->setValueToMatrixForUndriectedGraph(0, 5, 1);
cmap->setValueToMatrixForUndriectedGraph(1, 2, 3);
cmap->setValueToMatrixForUndriectedGraph(1, 5, 2);
cmap->setValueToMatrixForUndriectedGraph(2, 5, 8);
cmap->setValueToMatrixForUndriectedGraph(2, 3, 7);
cmap->setValueToMatrixForUndriectedGraph(3, 5, 4);
cmap->setValueToMatrixForUndriectedGraph(3, 4, 2);
cmap->setValueToMatrixForUndriectedGraph(4, 5, 9);
cmap->primTree(0);
cout << endl << endl;
cmap->kruskalTree();
/*cmap->printMatrix();
cout << endl;
cmap->depthFirstTraverse(0);
cmap->resetNode();
cout << endl;
cmap->breadthFirstTraverse(0);*/
delete cmap;
cmap = NULL;
}
//控制台运行得:
A
0-->5 1
F
5-->1 2
B
1-->2 3
C
5-->3 4
D
3-->4 2
E
0-->5 1
1-->5 2
3-->4 2
1-->2 3
3-->5 4
//--------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------