C++实现Prim与Kruskal最小生成树算法
Edge.h
#ifndef EDGE_H
#define EDGE_H
#include <iostream>
using namespace std;
class Edge
{
public:
Edge(int nodeIndexA = 0, int nodeIndexB = 0, int weightValue = 0);
~Edge();
int m_iNodeIndexA;
int m_iNodeIndexB;
int m_iWeightValue;
bool m_bSelected;
};
Edge::Edge(int nodeIndexA, int nodeIndexB, int weightValue)
{
m_iNodeIndexA = nodeIndexA;
m_iNodeIndexB = nodeIndexB;
m_iWeightValue = weightValue;
m_bSelected = false;
}
Edge::~Edge()
{
}
#endif // !EDGE_H
Node.h
#ifndef NODE_H
#define NODE_H
class Node
{
public:
Node(char data = 0);
char m_cData;
bool m_bIsVisited;
};
Node::Node(char data)
{
m_cData = data;
m_bIsVisited = false;
}
#endif // !NODE_H
CMap.h
#ifndef CMAP_H
#define CMAP_H
#include <iostream>
#include <vector>
#include <cstring>
#include "Node.h"
#include "Edge.h"
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 setValueToMatrixforUndirectedGraph(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 breadthFristTraverseImpl(vector<int> preVec); //广度优先遍历实现函数
int getMinEdge(vector<Edge> edgeVec); //获取最小边
bool isInSet(vector<int> &nodeSet, int target); //判断顶点是否在点集合中
void mergeNodeSet(vector<int> &nodeSetA, vector<int> nodeSetB); //合并两个顶点集合
private:
int m_iCapacity; //图中最多可以容纳的顶点数
int m_iNodeCount; //已经添加的顶点(结点)的个数 (索引)
Node *m_pNodeArray; //用来存放顶点数组
int *m_pMatrix; //用来存放邻接矩阵
Edge *m_pEdge;
};
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) );
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::setValueToMatrixforUndirectedGraph(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> curVec;
curVec.push_back(nodeIndex);
breadthFristTraverseImpl(curVec);
}
void CMap::breadthFristTraverseImpl(vector<int> preVec)
{
int value = 0;
vector<int> curVec;
for (int i = 0; i < (int)preVec.size(); i++)
{
for (int j = 0; j < m_iCapacity; j++)
{
getValueFromMatrix(preVec[i], j, value);
if (value != 0)
{
if (m_pNodeArray[j].m_bIsVisited)
{
continue;
}
else
{
cout << m_pNodeArray[j].m_cData << " ";
m_pNodeArray[j].m_bIsVisited = true;
curVec.push_back(j);
}
}
else
{
continue;
}
}
}
if (curVec.size() == 0)
{
return;
}
else
{
breadthFristTraverseImpl(curVec);
}
}
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::primTree(int nodeIndex)
{
int value = 0;
int edgeCount = 0;
vector<int> nodeVec;
vector<Edge> edgeVec;
cout << endl;
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);
edgeVec.push_back(edge);
}
}
}
//从可选便集合(edgeVec)中找出最小的边
int edgeIndex = getMinEdge(edgeVec);
edgeVec[edgeIndex].m_bSelected = true;
cout << edgeVec[edgeIndex].m_iNodeIndexA << "--" << edgeVec[edgeIndex].m_iNodeIndexB << " " << edgeVec[edgeIndex].m_iWeightValue << endl;
m_pEdge[edgeCount] = edgeVec[edgeIndex];
edgeCount++;
int nextNodeIndex = edgeVec[edgeIndex].m_iNodeIndexB;
//nodeIndex = nextNodeIndex;
nodeVec.push_back(nextNodeIndex);
m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
cout << m_pNodeArray[nextNodeIndex].m_cData << endl;
}
}
int CMap::getMinEdge(vector<Edge> edgeVec)
{
int minWeight = 0;
int edgeIndex = 0;
int i = 0;
for (; i < (int)edgeVec.size(); i++)
{
if (!edgeVec[i].m_bSelected)
{
minWeight = edgeVec[i].m_iWeightValue;
edgeIndex = i;
break;
}
}
if (minWeight == 0)
{
return -1;
}
for (; i < (int)edgeVec.size(); i++)
{
if (edgeVec[i].m_bSelected)
{
continue;
}
if (minWeight > edgeVec[i].m_iWeightValue)
{
minWeight = edgeVec[i].m_iWeightValue;
edgeIndex = i;
}
}
return edgeIndex;
}
void CMap::kruskalTree()
{
int value = 0;
int edgeCount = 0;
//定义存放结点集合的数组
vector< vector<int> > nodeSets;
//第一步:取出所有的边
vector<Edge> edgeVec;
for (int i = 0; i < m_iCapacity; i++)
{
for (int j = i + 1; j < m_iCapacity ; j++)
{
getValueFromMatrix(i, j, value);
if (value != 0)
{
Edge edge(i, j, value);
edgeVec.push_back(edge);
}
}
}
//第二步:从所有边中取出组成最小生成树的边
//1.找到算法结束条件
while (edgeCount < m_iCapacity - 1)
{
//2.从边集合中找到最小边
int minEdgeIndex = getMinEdge(edgeVec);
edgeVec[minEdgeIndex].m_bSelected = true;
//3.找出最小边连接的点
int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeIndexA;
int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeIndexB;
//4.找出点所在的点的集合
bool nodeAIsInSet = false;
bool nodeBIsInSet = false;
int nodeAInSetLabel = -1;
int nodeBInSetLabel = -1;
for (int i = 0; i < (int)nodeSets.size(); i++)
{
nodeAIsInSet = isInSet(nodeSets[i], nodeAIndex);
if (nodeAIsInSet)
{
nodeAInSetLabel = i;
}
}
for (int i = 0; i < (int)nodeSets.size(); i++)
{
nodeBIsInSet = isInSet(nodeSets[i], nodeBIndex);
if (nodeBIsInSet)
{
nodeBInSetLabel = i;
}
}
//5.根据点所在集合的不同做出不同的处理
if (nodeAInSetLabel == -1 && nodeBInSetLabel == -1)
{
vector<int> vec;
vec.push_back(nodeAIndex);
vec.push_back(nodeBIndex);
nodeSets.push_back(vec);
}
else if (nodeAInSetLabel == -1 && nodeBInSetLabel != -1)
{
nodeSets[nodeBInSetLabel].push_back(nodeAIndex);
}
else if (nodeAInSetLabel != -1 && nodeBInSetLabel == -1)
{
nodeSets[nodeAInSetLabel].push_back(nodeBIndex);
}
else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel != nodeBInSetLabel)
{
mergeNodeSet(nodeSets[nodeAInSetLabel], nodeSets[nodeBInSetLabel]);
for (int i = nodeBInSetLabel; i < (int)nodeSets.size() - 1; i++)
{
nodeSets[i] = nodeSets[i + 1];
}
}
else if (nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel)
{
continue;
}
m_pEdge[edgeCount] = edgeVec[minEdgeIndex];
edgeCount++;
cout << edgeVec[minEdgeIndex].m_iNodeIndexA << "---" << edgeVec[minEdgeIndex].m_iNodeIndexB << " " << edgeVec[minEdgeIndex].m_iWeightValue << endl;
}
}
bool CMap::isInSet(vector<int> &nodeSet, int target)
{
for (int i = 0; i < (int)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 < (int)nodeSetB.size(); i++)
{
nodeSetA.push_back(nodeSetB[i]);
}
}
#endif // !CMAP_H
main.cpp
#include "CMap.h"
#include "Node.h"
#include <stdlib.h>
int main()
{
CMap *pMap = new CMap(6);
Node *e1 = new Node('A');
Node *e2 = new Node('B');
Node *e3 = new Node('C');
Node *e4 = new Node('D');
Node *e5 = new Node('E');
Node *e6 = new Node('F');
pMap->addNode(e1);
pMap->addNode(e2);
pMap->addNode(e3);
pMap->addNode(e4);
pMap->addNode(e5);
pMap->addNode(e6);
pMap->setValueToMatrixforUndirectedGraph(0, 1, 6);
pMap->setValueToMatrixforUndirectedGraph(0, 4, 5);
pMap->setValueToMatrixforUndirectedGraph(0, 5, 1);
pMap->setValueToMatrixforUndirectedGraph(1, 2, 3);
pMap->setValueToMatrixforUndirectedGraph(1, 5, 2);
pMap->setValueToMatrixforUndirectedGraph(2, 5, 8);
pMap->setValueToMatrixforUndirectedGraph(2, 3, 7);
pMap->setValueToMatrixforUndirectedGraph(3, 5, 4);
pMap->setValueToMatrixforUndirectedGraph(3, 4, 2);
pMap->setValueToMatrixforUndirectedGraph(4, 5, 9);
pMap->printMatrix();
cout << endl;
pMap->depthFirstTraverse(0);
cout << endl;
pMap->resetNode();
pMap->breadthFirstTraverse(0);
cout << endl;
pMap->resetNode();
pMap->primTree(0);
cout << endl;
pMap->kruskalTree();
system("pause");
return 0;
}