源码:https://github.com/cjy513203427/C_Program_Base/tree/master/55.%E5%9B%BE
结点类Noded.h
不需要存储索引
#pragma once #ifndef NODE_H #define NODE_H #include<iostream> using namespace std; class Node { public: Node(char data = 0); char m_cData; bool m_IsVisited; }; #endif // !NODE_H
Node.cpp
将数据赋值给数据成员m_cData,是否访问置为否
#include"Node.h" Node::Node(char data) { m_cData = data; m_IsVisited = false; }
需要实现的方法
图类cMap.h
#pragma once #ifndef CMAP_H #define CMAP_H #include"Node.h" #include<vector> 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 breathFirstTraverseImpl(vector<int> preVec); private: bool getValueFromMatrix(int row,int col,int &val);//从矩阵中获取权值 void breathFirstTraverse(int nodeIndex);//广度优先遍历实现函数 private: int m_iCapacity;//图中最多可以容纳的顶点数 int m_iNodeCount;//已经添加的结点(顶点)个数 Node *m_pNodeArray;//用来存放顶点数组 int *m_pMatrix;//用来存放邻接矩阵 }; #endif // !CMAP_H
构造函数:
传入图容量参数给数据成员m_iCapacity
已经添加的结点数m_iNodeCount置为0
为顶点数组申请内存
申请m_iCapacity*m_iCapacity的矩阵
将矩阵元素全部置为0
cMap::cMap(int capacity) { m_iCapacity = capacity; m_iNodeCount = 0; m_pNodeArray = new Node[m_iCapacity]; m_pMatrix = new int[m_iCapacity*m_iCapacity]; for (int i = 0; i < m_iCapacity*m_iCapacity; i++) { m_pMatrix[i] = 0; } }
析构函数
删除顶点数组指针
删除邻接矩阵指针
cMap::~cMap() { delete []m_pNodeArray; delete []m_pMatrix; }
添加结点
判断传入的pNode参数是否为空,如果pNode为空,返回错误
将pNode的数据部分m_cData传入到以已经添加的结点个数为索引的顶点数组
已经添加结点个数++
返回正确结果
bool cMap::addNode(Node *pNode) { if (pNode == NULL) { return false; } m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData; m_iNodeCount++; return true; }
重置结点
将已经添加的结点的m_IsVisited置为未访问
void cMap::resetNode() { for (int i = 0; i < m_iNodeCount; i++) { m_pNodeArray[i].m_IsVisited = false; } }
为有向图设置邻接矩阵
判断行列的合法性
如果行小于0,行大于等于最大容量,返回错误
如果列小于0,列大于等于最大容量,返回错误
图如下:
上图的邻接矩阵如下:
以(A,B)即(0,1),0行1列,0*8+1=1。
满足row*m_iCapacity计算的索引
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; }
为无向图设置邻接矩阵
逻辑同上
col*m_iCapacity和row*m_iCapacity+col与主对角线成轴对称
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; }
从矩阵中获取权值
先判断行和列的合法性
行不能小于0,不能大于等于容量
列不能小于0,不能大于等于容量
获取当前索引的邻接矩阵,赋值给变量返回
返回正确结果
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; }
打印邻接矩阵
矩阵,用两层循环遍历
i是row,k就是col
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; } }
深度优先遍历
深度优先遍历相当于树的前序遍历
先直接输出当前指定索引的邻接矩阵的结点
讲m_IsVisited置为未访问
按序获取获取矩阵权值
如果权值不等于1,跳过本次循环
如果权值等于1,结点已访问,跳过本次循环,这里是无向图,这里判断结点是否访问是因为邻接矩阵的权值1成主对角线对称,防止A-B访问,再访问B-A的情况出现
如果未访问,进入递归,进入方法前两行,将结点输出,以此类推
看懂过程要打断点
void cMap::depthFirstTraverse(int nodeIndex) { int value = 0; cout << m_pNodeArray[nodeIndex].m_cData<<" "; m_pNodeArray[nodeIndex].m_IsVisited = true; for (int i = 0; i < m_iCapacity; i++) { getValueFromMatrix(nodeIndex,i,value); if (value == 1) { if (m_pNodeArray[i].m_IsVisited == true) { continue; } else { depthFirstTraverse(i); } } else { continue; } } }
广度优先遍历
广度优先遍历相当于按层次的树的前序遍历
思路:将上层结点放到一个vector里,该结点的下层结点再放到一个vector里
void cMap::breadthFirstTraverse(int nodeIndex) { cout << m_pNodeArray[nodeIndex].m_cData<<" "; m_pNodeArray[nodeIndex].m_IsVisited = true; vector<int> currentVec; currentVec.push_back(nodeIndex); breathFirstTraverseImpl(currentVec); } void cMap::breathFirstTraverseImpl(vector<int> preVec) { int value = 0; vector<int> curVec; for (int j = 0; j < (int)preVec.size(); j++) { for (int i = 0; i < m_iNodeCount; i++) { getValueFromMatrix(preVec[j],i,value); if (value != 0) { if (m_pNodeArray[i].m_IsVisited) { continue; } else { cout << m_pNodeArray[i].m_cData << " "; m_pNodeArray[i].m_IsVisited = true; curVec.push_back(i); } } } } if (curVec.size() == 0) { return; } else { breathFirstTraverseImpl(curVec); } }