数据结构之图(C++)--邻接矩阵表示(一)
来源:互联网 发布:select算法 编辑:程序博客网 时间:2024/04/30 15:27
数据结构之图(C++)–邻接矩阵表示(一)
基本概念
简单地说,图是一个用线或边链接爱一起的顶点或节点的集合。严格地说,图是有限集V和E的有序对,即G=(V,E),其中V的元素称为顶点(也称节点或点),E的元素称为边(也叫弧或线)。每一条边链接两个不同的顶点,而且用元组(i,j)来表示,其中i和j是边所连接的两个顶点。
- 图的术语:顶点,边,邻接,关联,度,回路,路径,连通构件,生成树
- 图的类型:无向图,有向图和加权图
- 图的常用描述方式:邻接矩阵,矩阵邻接表和邻接链表
- 图的搜索方式:广度优先搜索和深度优先搜索
- 相关算法:拓扑排序,二分覆盖,最短路径,最小生成树,旅行推销员等等
图的相关定义
如果图的所有边都是无向边(不带箭头的边),那么该图叫做无向图。如果图的所有边都是有向边,那么该图叫做有向图。
一个图不能有重复的边。在有向图中,任意两个顶点 i 和 j 之间,从顶点 i 到顶点 j 最多有一条边。在无向图中,任意两个顶点之间,最多只能有一条边。而且一个图不能包含自连边(即“顶点”自己与自己连线)
当我们给每条边赋予一个表示成本的值,我们称之为权(例如,高速公路上,从A地到B地要走300公里,A地到C地要走500公里,这里的300和500可以看成是AB和AC边的权)。这是的图我们成为加权有向图或加权五向图。
度:一个顶点i相关联的边数称为该顶点的度。
有向图中的入度和出度
- 入度: 关联至该顶点的边数。
- 出度:关联于该顶点的边数
例如上面的有向图,顶点3的入度为2, 出度为2。顶点5的入度为2,出度为1.
图的相关操作
抽象类graph
template <typename T>class graph{public: virtual ~graph() { } // ADT 方法 virtual int numberOfVertices() const = 0; // 返回图的顶点数目 virtual int numberOfEdges() const = 0; // 返回图的边数 virtual bool existsEge(int, int) const = 0; // 如果边(i, j)存在,返回true virtual void insertEdge(edge<T>*) = 0; // 插入边 virtual void eraseEdge(int, int) = 0; // 删除边 virtual int degree(int) const = 0; // 返回顶点的i的度 virtual int inDegree(int) const = 0; // 返回顶点i的入度 virtual int outDegree(int) const = 0; // 返回顶点i的出度 virtual bool directed() const = 0; // 如果是有向图返回true virtual bool weighted() const = 0; // 如果是加权图返回true virtual vertexIterator<T>* interator(int) = 0; // 访问指定顶点的相邻顶点};
上述的相关操作将在下一节讲解
邻接矩阵
一个n顶点图G=(V,E)的邻接矩阵是一个n×n的矩阵,其中每个元素是0或者1.
- 无向图中元素定义:A(i,j) = 1 (如果(i,j)∈E或(j,i)∈E) 或者 A(i,j)= 0
无向图的邻接矩阵是对称的。
例如下面表示的就是无限图有向图元素定义:A(i,j)= 1 (如果(i,j)∈E)或者 A(i,j)= 0
代码实现
// val值默认为1bool Graph::setDirectGraph(int row, int col, int val){ if (row < 0 || row > m_iCapacity || col < 0 || col > m_iCapacity) { return false; } m_pMatrix[row * m_iCapacity + col] = val; return true;}bool Graph::setUndiretGraph(int row, int col, int val){ if (row < 0 || row >= m_iCapacity || col < 0 || col >= m_iCapacity) { return false; } m_pMatrix[row * m_iCapacity + col] = val; m_pMatrix[col * m_iCapacity + row] = val; return true;}
图的顶点类
类中只包含了构造函数用于设置顶点的信息,可以自行扩展,例如加入权值
// 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__
图的边类
对于边来说我们一边保存边的两端的顶点,和边的权值
// Edge.h#ifndef EDGE_H__#define EDGE_H__class Edge{public: Edge(int nodeIndexA = 0, int nodeIndexB = 0, int weightValue = 0); int m_iNodeIndexA; // 顶点A的索引 int m_iNodeIndexB; // 顶点B的索引 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 //EDGE_H__
图的Graph类
#include <vector>#include "Node.h"#include "Edge.h"using namespace std;class Graph{public: Graph(int capacity); ~Graph(); bool addNode(Node* pNode); // 添加顶点 void resetNode(); // 重置顶点(遍历一次会导致m_bIsVisited=true,需要重置将其设为false) bool setDirectGraph(int row, int col, int val = 1); // 设置有向图 bool setUndiretGraph(int row, int col, int val = 1); // 设置无向图 void depthTraverse(int nodeIndex); // 深度优先搜索 void breadthTraverse(int nodeIndex); // 广度优先搜索 void printMatrix(); //打印邻接矩阵 //void primTree(int nodeIndex); //普利姆生成树 //void kruskalTree(); //克鲁斯卡尔算法生成树private: bool getValueFromMatrix(int row, int col, int& val); void breadthTraverseImpl(vector<int> preVec);private: int m_iCapacity; // 图的最大容量 int m_iNodeCount; // 顶点的个数 int* m_pMatrix; // 邻接矩阵的指针 Edge* m_pEdge; // 边的指针 Node* m_pNodeArray; // 数组中顶点的指针};#endif //GRAPH_H__
构造函数和析构函数
Graph::Graph(int capacity){ m_iCapacity = capacity; m_iNodeCount = 0; m_pMatrix = new int[m_iCapacity * m_iCapacity]; // 建立一个m_iCapacity*m_iCapacity大小的数组 m_pNodeArray = new Node[m_iCapacity]; memset(m_pMatrix, 0, m_iCapacity * m_iCapacity * sizeof(int)); m_pEdge = new Edge[m_iCapacity - 1];}Graph::~Graph(){ delete[] m_pMatrix; delete[] m_pNodeArray; delete[] m_pEdge;}
深度优先搜索
深度优先搜索有点类似二叉搜索树中的前序遍历
如图,利用深度优先搜素遍历:A-B-C-D-E-F-G-H
代码利用递归实现
void Graph::depthTraverse(int nodeIndex){ // 每次递归输出该节点信息 int value = 0; cout << m_pNodeArray[nodeIndex].m_cData << " "; // 将节点设置成true m_pNodeArray[nodeIndex].m_bIsVisited = true; // for (int i = 0; i < m_iCapacity; i++) { getValueFromMatrix(nodeIndex, i, value); if (value == 1) { if (m_pNodeArray[i].m_bIsVisited == true) { continue; } else { depthTraverse(i); } } else { continue; } }}
广度优先搜索
从一个顶点开始,搜索所有可以到达顶点的方法叫做广度优先搜索。
如图,利用广度优先搜索遍历:A-B-F-C-E-F-G-H-D
代码实现
void Graph::breadthTraverse(int nodeIndex){ cout << m_pNodeArray[nodeIndex].m_cData << " "; m_pNodeArray[nodeIndex].m_bIsVisited = true; vector<int> curVec; curVec.push_back(nodeIndex); breadthTraverseImpl(curVec);}bool Graph::getValueFromMatrix(int row, int col, int& val){ if (row < 0 || row >= m_iCapacity || col < 0 || col >= m_iCapacity) { return false; } val = m_pMatrix[row * m_iCapacity + col]; return true;}void Graph::breadthTraverseImpl(vector<int> preVec){ int value = 0; vector<int> curVec; for (unsigned j = 0; j < 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 == true) { continue; } else { cout << m_pNodeArray[k].m_cData << " "; m_pNodeArray[k].m_bIsVisited = true; curVec.push_back(k); } } } } if (curVec.size() == 0) { return; } else { breadthTraverseImpl(curVec); }}
其他代码
bool Graph::addNode(Node* pNode){ if (pNode == NULL) { return false; } m_pNodeArray[m_iNodeCount].m_cData = pNode->m_cData; m_iNodeCount++; return false;}void Graph::resetNode(){ for (int i = 0; i < m_iCapacity; i++) { m_pNodeArray[i].m_bIsVisited = false; }}void Graph::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; }}bool Graph::getValueFromMatrix(int row, int col, int& val){ if (row < 0 || row >= m_iCapacity || col < 0 || col >= m_iCapacity) { return false; } val = m_pMatrix[row * m_iCapacity + col]; return true;}
- 数据结构之图(C++)--邻接矩阵表示(一)
- 数据结构(C实现)------- 图的邻接矩阵表示
- 数据结构(C实现)------- 图的邻接矩阵表示
- 数据结构之---C语言实现图的数组(邻接矩阵)存储表示
- 数据结构C语言版之邻接矩阵(遍历)
- 数据结构与C语言实现(八)——图(上):邻接矩阵表示图
- 图的邻接矩阵c语言表示(无向网)---《数据结构》算法7.2
- 数据结构之图的存储表示(邻接矩阵、邻接表和边集数组)
- 数据结构(C++)<图的邻接矩阵存储>
- 数据结构,图的邻接矩阵表示
- 数据结构-图的邻接矩阵表示
- 数据结构的C实现_图_邻接矩阵表示
- 图论之图形的表示方法(一)-数组表示法/相邻矩阵法/邻接矩阵法
- C++面向对象的数据结构之 图(邻接矩阵表示)
- 详解数据结构——图之邻接矩阵表示法
- 数据结构(C语言版)规范代码之图(邻接矩阵与邻接表)
- 数据结构之图-邻接矩阵
- 数据结构(C++)—— 图(邻接矩阵)
- Swift hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView?
- 动态多变的tab菜单底部
- 分治算法
- Linux 的 Socket IO 模型
- python爬虫从0到1遇到问题及解决方向
- 数据结构之图(C++)--邻接矩阵表示(一)
- 【Android图像处理】lomo滤镜(效果)
- 排序算法——2
- QT多国语言测试程序
- 使用ssh-keygen,不用密码远程登录
- 总结
- 变量的存储类别详解二
- 解析plist 创建模型数据的正确理解
- Weex入门与进阶指南