您的位置:首页 > 编程语言 > C语言/C++

使用C++邻接矩阵实现图的存储、Prim、Kruskal算法

2016-10-08 21:37 447 查看
1、创建Node.h 定义图的顶点

#ifndef NODE_H
#define NODE_H
class Node{
public:
Node(char data=0);
char m_cData;
bool m_bIsVisited;
};
#endif // NODE_H

2、创建Node.cpp 实现顶点的定义
#include "Node.h"
Node::Node(char data){
m_cData = data;
m_bIsVisited = false;
}3、创建CMap.h 实现图的数据结构的定义
#ifndef CMAP_H
#define CMAP_H
#include <vector>
#include "Node.h"
#include "Edge.h"
using namespace std;
class CMap{
public:
CMap(int campacity);
~CMap();
bool addNode(Node *pNode);
void resetNode(); //将所有顶点的访问标示设置为false
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 breadFirstTraverse(int nodeindex);
void primTree(int nodeindex);
void kluskalTree();

private:
bool getValueFromMatrix(int row,int col,int &val);
void breadFirstTraverseImp(vector<int> preVec); //广度优先遍历实现函数
int getMinEdge(vector<Edge> edgeVec);
bool isInSet(vector<int> nodeSet,int target);
void mergeNodeSet(vector<int> &nodeSetA,vector<int> nodeSetB);
int m_iCampacity; //图中最多可容纳的顶点的个数
int m_iNodeCount; //已经添加的顶点的个数
Node *m_pNodeArray; //用来存放顶点数组
int *m_pMatrix; //用来存放邻接矩阵
Edge *m_pEdgeArray; //最小生成树选中边的集合

};
#endif // CMAP_H

4、创建CMap.cpp 实现图的定义
#include "CMap.h"
#include "Node.h"
#include "Edge.h"
#include <cstring>
#include <iostream>
using namespace std;
CMap::CMap(int campacity){
m_iCampacity = campacity;
m_iNodeCount = 0;
m_pNodeArray = new Node[campacity];
m_pMatrix = new int[m_iCampacity * m_iCampacity];
memset(m_pMatrix,0,m_iCampacity * m_iCampacity * sizeof(int));
m_pEdgeArray = new Edge[m_iCampacity - 1];
}
CMap::~CMap(){
delete[] m_pNodeArray;
delete[] m_pMatrix;
delete[] m_pEdgeArray;
}
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_iCampacity;i++){
m_pNodeArray[i].m_bIsVisited = false;

}
}
/**
带有默认参数的构造函数只需在声明时指定默认参数值,定义则不必指明默认参数的值
**/
bool CMap::setValueToMatrixForDirectedGraph(int row,int col,int val){
if(row < 0 || row >= m_iCampacity || col < 0 || col >= m_iCampacity)
return false;
m_pMatrix[row * m_iCampacity + col] = val;
return true;
}
bool CMap::setValueToMatrixForUndirectedGraph(int row,int col,int val){
if(row < 0 || row >= m_iCampacity || col < 0 || col >= m_iCampacity)
return false;
m_pMatrix[row * m_iCampacity + col] = val;
m_pMatrix[col * m_iCampacity + row] = val;
return true;
}
void CMap::printMatrix(){
for(int i = 0; i < m_iCampacity;i++){
for(int j = 0; j < m_iCampacity;j++){
cout<<m_pMatrix[i * m_iCampacity + j]<<"\t";
}
cout<<endl;
}
}
bool CMap::getValueFromMatrix(int row,int col,int &val){
if(row < 0 || row >= m_iCampacity || col < 0 || col >= m_iCampacity)
return false;
val = m_pMatrix[row * m_iCampacity + col];
return true;
}
void CMap::depthFirstTraverse(int nodeindex){
cout<<m_pNodeArray[nodeindex].m_cData<<" ";
m_pNodeArray[nodeindex].m_bIsVisited = true;
int value = 0;
for(int i = 0;i < m_iCampacity;i++){
//value = m_pNodeArray[nodeindex + 1].c_Data;
getValueFromMatrix(nodeindex,i,value);
if(value == 1){
if(m_pNodeArray[i].m_bIsVisited){
continue;
}else{
depthFirstTraverse(i);
}
}else{
continue;
}
}
}
void CMap::breadFirstTraverse(int nodeindex){
if(nodeindex < 0 || nodeindex >= m_iCampacity)
return;
cout<<m_pNodeArray[nodeindex].m_cData<<" ";
m_pNodeArray[nodeindex].m_bIsVisited = true;
vector<int> curVec;
curVec.push_back(nodeindex);
breadFirstTraverseImp(curVec); //传递容器参数直接传递即可
}
void CMap::breadFirstTraverseImp(vector<int> preVec){
int value;
vector<int> curVec;
for(int i = 0;i < (int)preVec.size();i++){
for(int j = 0;j < m_iCampacity;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){
breadFirstTraverseImp(curVec);
}
}
/**最小生成树 Prim算法相关函数**/
void CMap::primTree(int nodeindex){
int value;
vector<int> nodeVec; //选中点的集合
vector<Edge> edgeVec; //备选边的集合
int edgeCount = 0;
nodeVec.push_back(nodeindex);
m_pNodeArray[nodeindex].m_bIsVisited = true;
cout<<m_pNodeArray[nodeindex].m_cData<<endl;
while(edgeCount < m_iCampacity - 1){
int temp = nodeVec.back();
for(int i = 0;i < m_iCampacity;i++){
getValueFromMatrix(temp,i,value);
if(value != 0){
if(m_pNodeArray[i].m_bIsVisited){
continue;
}else{
Edge edge(temp,i,value); //什么时候用new,什么时候不用new,这里为什么不用
edgeVec.push_back(edge);
}
}else{
continue;
}
}
//int len = edgeVec.size();
//从可选边集合中选出最小边
int edgeIndex = getMinEdge(edgeVec);
edgeVec[edgeIndex].m_bSelected = true;
cout<<edgeVec[edgeIndex].m_iNodeA<<"----"<<edgeVec[edgeIndex].m_iNodeB;
cout<<" weight:"<<edgeVec[edgeIndex].m_iWeightValue<<endl;
//cout<<edgeVec[edgeIndex].m_iWeightValue<<endl;
m_pEdgeArray[edgeCount] = edgeVec[edgeIndex];
edgeCount++;
int nextNodeIndex = edgeVec[edgeIndex].m_iNodeB;
nodeVec.push_back(nextNodeIndex);
m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
cout<<m_pNodeArray[nextNodeIndex].m_cData<<endl;

}
}
int CMap::getMinEdge(vector<Edge> edgeVec){
int edgeIndex = 0;
int minWeight = 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;
}else{
if(edgeVec[i].m_iWeightValue < minWeight){
minWeight = edgeVec[i].m_iWeightValue;
edgeIndex = i;
}
}
}
return edgeIndex;
}
//最小生成树 kluskal算法
void CMap::kluskalTree(){
int value = 0;
int edgeCount = 0;
//定义存放节点集合的数组
vector< vector<int> > nodeSets;//点集合的集合
vector<Edge> edgeVec;
//第一步:取出所有边
for(int i = 0;i < m_iCampacity;i++){ //轮训矩阵上三角
for(int j = i+1;j < m_iCampacity;j++){
getValueFromMatrix(i,j,value);
if(value != 0){
Edge edge(i,j,value);
edgeVec.push_back(edge);
}
}
}
//第二步:从所有边中取出组成最小生成树的边
//1、找到算法的结束条件
while(edgeCount < m_iCampacity - 1){
//2、从边集合中找到最小边
int minEdgeIndex = getMinEdge(edgeVec);
edgeVec[minEdgeIndex].m_bSelected = true;
//3、找出最小边连接的点
int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeA;
int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeB;
//4、找出点所在的集合
bool isAInSet = false;
bool isBInSet = false;
int nodeAInSetLabel = -1;
int nodeBInSetLabel = -1;
for(int i = 0;i < (int)nodeSets.size();i++){
isAInSet = isInSet(nodeSets[i],nodeAIndex);
if(isAInSet){
nodeAInSetLabel = i;
}
}
for(int i = 0;i < (int)nodeSets.size();i++){
isBInSet = isInSet(nodeSets[i],nodeBIndex);
if(isBInSet){
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 == nodeBInSetLabel){
continue;
}
m_pEdgeArray[edgeCount] = edgeVec[minEdgeIndex];
edgeCount++;
cout<<edgeVec[minEdgeIndex].m_iNodeA<<"---"<<edgeVec[minEdgeIndex].m_iNodeB;
cout<<" weight:"<<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]);
}
}

5、如果要使用Prim和Kruskal算法构造最小生成树还要创建Edge.h 和Edge.cpp
Edge.h

#ifndef EDGE_H
#define EDGE_H
class Edge{
public:
int m_iNodeA;
int m_iNodeB;
bool m_bSelected;
Edge(int nodeA=0,int nodeB=0,int weightValue=0);
int m_iWeightValue;

};
#endif // EDGE_H
Edge.cpp
#include "Edge.h"
Edge::Edge(int nodeA,int nodeB,int weightValue){
m_iNodeA = nodeA;
m_iNodeB = nodeB;
m_iWeightValue = weightValue;
m_bSelected = false;
}


6、创建main.cpp 检验定义的正确性

#include <iostream>
#include "CMap.h"
using namespace std;
/**
ABCDEFGH
01234567
A
/ \
B D
/ \ / \
C F G-H
\ /
E

A
/ | \
B---F---E
\ /\ /
C--D
ABCDEF
012345
A-B 6 A-E 5 A-F 1
B-C 3 B-F 2
C-F 8 C-D 7
D-F 4 D-E 2
E-F 2

**/
int main()
{
/**
//树的基本操作检验
CMap *cmap = new CMap(8);
Node *node1 = new Node('A');
Node *node2 = new Node('B');
Node *node3 = new Node('C');
Node *node4 = new Node('D');
Node *node5 = new Node('E');
Node *node6 = new Node('F');
Node *node7 = new Node('G');
Node *node8 = new Node('H');

cmap->addNode(node1);
cmap->addNode(node2);
cmap->addNode(node3);
cmap->addNode(node4);
cmap->addNode(node5);
cmap->addNode(node6);
cmap->addNode(node7);
cmap->addNode(node8);

cmap->setValueToMatrixForUndirectedGraph(0,1);
cmap->setValueToMatrixForUndirectedGraph(0,3);
cmap->setValueToMatrixForUndirectedGraph(1,2);
cmap->setValueToMatrixForUndirectedGraph(1,5);
cmap->setValueToMatrixForUndirectedGraph(3,6);
cmap->setValueToMatrixForUndirectedGraph(3,7);
cmap->setValueToMatrixForUndirectedGraph(6,7);
cmap->setValueToMatrixForUndirectedGraph(2,4);
cmap->setValueToMatrixForUndirectedGraph(4,5);

cmap->printMatrix();
cmap->depthFirstTraverse(0);
cout<<endl;
cmap->resetNode();
cout<<endl;
cmap->breadFirstTraverse(0);**/

//prim 算法检验
CMap *pMap = new CMap(6);
Node *pNodeA = new Node('A');
Node *pNodeB = new Node('B');
Node *pNodeC = new Node('C');
Node *pNodeD = new Node('D');
Node *pNodeE = new Node('E');
Node *pNodeF = new Node('F');

pMap->addNode(pNodeA);
pMap->addNode(pNodeB);
pMap->addNode(pNodeC);
pMap->addNode(pNodeD);
pMap->addNode(pNodeE);
pMap->addNode(pNodeF);

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->primTree(0);
cout<<"------------------------------"<<endl;
pMap->kluskalTree();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: