有向图和无向图的数组C++实现
源码: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 = );
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 = );//为有向图设置邻接矩阵
bool setValueToMatrixForUndirectedGraph(int row, int col, int val = );//为无向图设置邻接矩阵 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 = ;
m_pNodeArray = new Node[m_iCapacity];
m_pMatrix = new int[m_iCapacity*m_iCapacity];
for (int i = ; i < m_iCapacity*m_iCapacity; i++)
{
m_pMatrix[i] = ;
}
}
析构函数
删除顶点数组指针
删除邻接矩阵指针
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 = ; 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< || row>=m_iCapacity)
{
return false;
}
if (col < || 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< || row >= m_iCapacity)
{
return false;
}
if (col < || 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< || row >= m_iCapacity)
{
return false;
}
if (col < || col >= m_iCapacity)
{
return false;
}
val = m_pMatrix[row*m_iCapacity+col];
return true;
}
打印邻接矩阵
矩阵,用两层循环遍历
i是row,k就是col
void cMap::printMatrix()
{
for (int i=;i<m_iCapacity;i++)
{
for (int k = ; 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 = ;
cout << m_pNodeArray[nodeIndex].m_cData<<" ";
m_pNodeArray[nodeIndex].m_IsVisited = true; for (int i = ; i < m_iCapacity; i++)
{
getValueFromMatrix(nodeIndex,i,value);
if (value == )
{
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 = ;
vector<int> curVec; for (int j = ; j < (int)preVec.size(); j++)
{
for (int i = ; i < m_iNodeCount; i++)
{
getValueFromMatrix(preVec[j],i,value);
if (value != )
{
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() == )
{
return;
}
else
{
breathFirstTraverseImpl(curVec);
}
}
有向图和无向图的数组C++实现的更多相关文章
- 概率图模型之有向图与无向图之间的关系 I map D map perfect map(完美图) 概念
我们已经讨论了有向图和无向图框架下的概率模型,那么我们有必要讨论一下它们二者的关系.
- 图论 Make Unique:有向图和无向图的一些算法
计算机科学入门资料之一的<算法与数据结构-C语言版>,覆盖了基础算法的几乎所有分支,其中的一个典型分支为图理论. 一个简介:图论基础-图数据结构基础 一个简洁的博客:图论基础,简列一本书 ...
- tarjan——有向图、无向图
强连通块只存在于有向无环图DAG中 实际上low[i]的理解是:一个强连通块在dfs搜索树中子树的根节点 //把一个点当成根提溜出来,抖搂抖搂成一棵树 void dfs(int u) { //记录df ...
- 有向图与无向图的合并操作区别D(递归与并查集)
有向图的合并,典型问题:通知小弟(信息只能单向传播)https://www.nowcoder.com/acm/contest/76/E 无向图的合并,典型问题:修道路问题 由于无向图只要二者有联系即可 ...
- WBS任务分解中前置任务闭环回路检测:有向图的简单应用(C#)
1 场景描述 系统中用到了进度计划编制功能,支持从project文件直接导入数据,并能够在系统中对wbs任务进行增.删.改操作.wbs任务分解中一个重要的概念就是前置任务,前置任务设置确定了不同任务项 ...
- Java数据结构和算法(十五)——无权无向图
前面我们介绍了树这种数据结构,树是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合,把它叫做“树”是因为它看起来像一棵倒挂的树,包括二叉树.红黑树.2-3-4树.堆等各种不同的 ...
- 有向网络(带权的有向图)的最短路径Dijkstra算法
什么是最短路径? 单源最短路径(所谓单源最短路径就是只指定一个顶点,最短路径是指其他顶点和这个顶点之间的路径的权值的最小值) 什么是最短路径问题? 给定一带权图,图中每条边的权值是非负的,代表着两顶点 ...
- UVA 1660 Cable TV Network 电视网络(无向图,点连通度,最大流)
题意:给一个无向图,求其点连通度?(注意输入问题) 思路: 如果只有1个点,那么输出“1”: 如果有0条边,那么输出“0”: 其他情况:用最大流解决.下面讲如何建图: 图的连通度问题是指:在图中删去部 ...
- POJ2186(有向图缩点)
Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 28379 Accepted: 11488 De ...
随机推荐
- Autofac的简单使用
今天记录一下学习Autofac的过程. 之前对IoC与DI一直很迷糊,今天研究了前辈们的文章后,才对IoC和DI有了一个初步的了解.感谢前辈们的无私奉献! 文章地址: 依赖注入和控制反转的理解,写的太 ...
- Asp.Net Core下的两种路由配置方式
与Asp.Net Mvc创建区域的时候会自动为你创建区域路由方式不同的是,Asp.Net Core下需要自己手动做一些配置,但更灵活了. 我们先创建一个区域,如下图 然后我们启动访问/Manage/H ...
- 【QTP专题-优化】VBS脚本启动QTP并运行测试
使用vbs脚本启动QTP并运行测试,startQTP.vbs '******************************************************************** ...
- Python操作配置文件configparser模块
在实际的开发过程中,我们常有操作ini格式和conf格式配置文件的操作,Python为我们提供了configparser模块,方便我们对配置文件进行读写操作. config.ini配置文件内容如下: ...
- 深入了解java虚拟机(JVM) 第三章 内存区域----堆空间
一.堆的含义 jvm堆的区域主要是用来存放对象的实例,它的空间大小是JVM内存区域中占比重最大的,也是jvm最大的内存管理模块,最重要的是,这个区域是垃圾收集器主要管理的区域,这意味着我们在考虑垃圾回 ...
- OCP 12c最新考试原题及答案(071-8)
8.(5-4) choose the best answer:You need to produce a report where each customer's credit limit has b ...
- AutoCAD.Net圆弧半径标注延长线
#region 注册RegApp public static void CheckRegApp(string regapptablename) { Database db = HostApplicat ...
- PHP查询数据库,对象结果集转化为数组
$row = $this->db->get();//得出对象结果集 $result = array(); if($row) { //转化为数组 while($value = $row-&g ...
- python 元类以及练习
''' # 知识储备exec() # 参数1:字符串形式的命令 # 参数2:全局作用域(字典形式),如果不指定默认就使用globals() # 参数3:局部作用域(字典形式),如果不指定默认就使用lo ...
- unity+Helios制作360°全景VR视频
unity版本 unity2017.2.0 Helios版本:Helios 1.3.6 ffmpeg:ffmpeg-20180909-404d21f-win64-static(地址:https:// ...