一、图的基本概念及存储方式
图的存储结构:
邻接矩阵:
struct Node {
顶点索引;
顶点数据;
}
struct Map {
顶点数组;
邻接矩阵;
}
邻接表–链式存储
struct Node {
顶点索引;
该顶点弧链表的头节点;
顶点数据;
}
struct Arc {
指向的顶点索引;
指向下一条弧的指针;
弧信息;
}
struct Map {
顶点数组;
}
十字链表–链式存储
struct Arc {
弧尾顶点索引;
弧头顶点索引;
指向下一条弧头相同的弧的指针;
指向下一条弧尾相同的弧的指针;
弧信息;
}
struct Node {
顶点索引;
顶点数据;
第一条入弧结点指针;
第一条出弧结点指针;
}
struct Map {
顶点数组;
}
邻接多重表 – 链表存储(无向图)
struct Arc {
顶点A索引;
顶点B索引;
连接A的下一条边的指针;
连接B的下一条边的指针;
边信息;
}
struct Node {
顶点索引;
顶点数据;
第一条边结点指针;
}
struct Map {
顶点数组;
}
二、图的基本操作与遍历
图的遍历:深度优先搜素(前序优先搜索) 、广度优先搜索**
CMap.h
#define CMPA_H
#include<vector>
#include "Edge.h"
#include "Node.h"
#include<iostream>
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); //普利姆生成树
private:
bool isInSet(vector<int> nodeSet,int target);
void mergeNodeSet(vector<int> &nodeSetA,vector<int> nodeSetB);
int getMinEdge(vector<Edge> edgeVec);
bool getValueFromMatrix(int row, int col, int &val); //从矩阵中获取权值
void breadthFirstTraverseImpl(vector<int> preVec); //广度优先遍历实现函数
int m_iCapacity; //图中最多可以容纳的顶点数
int m_iNodeCount; // 已经添加的顶点(结点)个数
Node *m_pNodeArray; //用来存放顶点数组
int *m_pMatrix; //用来存放邻接矩阵
Edge *m_pEdge;
};
CMap::CMap(int capacity) {
m_iCapacity = 0;
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;
}
void CMap::resetNode() {
for(int i = 0; i < m_iNodeCount; i++) {
m_pNodeArray[i].m_bIsVisited = false;
}
}
bool CMap::addNode(Node *pNode) {
m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData;
m_iNodeCount++;
return true;
}
bool CMap::setValueToMatrixForDirectedGraph(int row,int col,int val) {
m_pMatrix[row*m_iCapacity + col] = val;
return true;
}
bool CMap::setValueToMatrixForUndirectedGraph(int row,int col,int val) {
m_pMatrix[row*m_iCapacity + col] = val;
m_pMatrix[col*m_iCapacity + row] = val;
return true;
}
bool CMap::getValueFromMatrix(int row, int col, int &val) {
val = m_pMatrix[row*m_iCapacity + col];
return true;
}
void CMap::breadthFirstTraverseImpl(vector<int> preVec) {
int value = 0;
vector<int> curVec;
for(int j = 0; j < (int)preVec.size(); j++) {
for(int k = 0; k < m_iCapacity; k++) {
getValueFromMatrix(preVec[j],k,value);
if(value != 0) {
if(m_pNodeArray[k].m_bIsVisited) {
continue;
} else {
cout << m_pNodeArray[k].m_cData << " ";
m_pNodeArray[k].m_bIsVisited = true;
curVec.push_back(k);
}
}
}
}
if(curVec.size() == 0) {
return;
} else {
breadthFirstTraverseImpl(curVec);
}
}
void CMap::printMatrix() {
for(int i = 0; i < m_iCapacity; i++) {
for(int k = 0; k < m_iCapacity; k++) {
cout << m_pMatrix[i*m_iCapacity + k];
}
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);
}
}
}
}
void CMap::breadthFirstTraverse(int nodeIndex) {
cout << m_pNodeArray[nodeIndex].m_cData << " ";
m_pNodeArray[nodeIndex].m_bIsVisited = true;
vector<int> curVec;
curVec.push_back(nodeIndex);
breadthFirstTraverseImpl(curVec);
}
Node.h
#ifndef NODE_H
#define NODE_H
#include<iostream>
using namespace std;
class Node{
public:
Node(char data = 0);
char m_cData;
bool m_bIsVisited;
};
Node::Node(char data) {
m_cData = data;
m_bIsVisited = false;
}
#endif
三、图的最小生成树算法
普利姆算法
Edge.h
#ifndef EDGE_H
#define EDGE_H
class Edge {
public:
Edge(int nodeIndexA = 0,int nodeIndexB = 0,int weightValue = 0);
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;
}
#endif
CMap.h
CMap::CMap(int capacity) {
m_iCapacity = 0;
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];
}
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);
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);
}
}
}
//从可选边集合中找出最小的边
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;
nodeVec.push_back(nextNodeIndex);
m_pNodeArray[nextNodeIndex].m_bIsVisited = true;
}
}
int CMap::getMinEdge(vector<Edge> edgeVec) {
int minWeight = 0;
int edgeIndex = 0;
for(int i = 0; i < edgeVec.size(); i++) {
if(!edgeVec[i].m_bSelected) {
minWeight = edgeVec[i].m_iWeightValue;
edgeIndex = i;
}
}
if(minWeight == 0) {
return -1;
}
for(int i = 0; i < 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;
}
克鲁斯卡尔算法
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 k = i+1; k < m_iCapacity; k++) {
getValueFromMatrix(i,k,value);
if(value != 0) {
Edge edge(i,k,value);
edgeVec.push_back(edge);
}
}
}
//从可选边集合中找出最小的边
while (edgeCount < m_iCapacity - 1) {
int minEdgeIndex = getMinEdge(edgeVec);
edgeVec[minEdgeIndex].m_bSelected = true;
int nodeAIndex = edgeVec[minEdgeIndex].m_iNodeIndexA;
int nodeBIndex = edgeVec[minEdgeIndex].m_iNodeIndexB;
bool nodeAIsInSet = false;
bool nodeBIsInSet = false;
int nodeAInSetLabel = -1;
int nodeBInSetLabel = -1;
for(int i = 0; i < nodeSets.size(); i++) {
nodeAIsInSet = isInSet(nodeSets[i],nodeAIndex);
if(nodeAIsInSet) {
nodeAInSetLabel = i;
}
}
for(int i = 0; i < nodeSets.size(); i++) {
nodeBIsInSet = isInSet(nodeSets[i],nodeBIndex);
if(nodeBIsInSet) {
nodeBInSetLabel = i;
}
}
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 k = nodeBInSetLabel; k < (int)nodeSets.size()-1; k++) {
nodeSets[k] = nodeSets[k + 1];
}
}
else if(nodeAInSetLabel != -1 && nodeBInSetLabel != -1 && nodeAInSetLabel == nodeBInSetLabel) {
continue;
}
m_pEdge[edgeCount] = edgeVec[minEdgeIndex];
edgeCount++;
}
}
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]);
}
}