有向图和无向图的数组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 ...
随机推荐
- Mathcad操作tips:算式输入、变量定义与计算
算式输入 1. 数字与符号相乘,输入时不必手动输入乘号(“*”). 2. 以下有助于算式的可视化:a. 使用Math工具栏输入,并合理使用tab键:b. 合理使用空格键. 3. 输入开根号时,可用快捷 ...
- Elasticsearch(1.1.1)基础教程pdf
基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT) Elasticsearch是一个接近实时的搜索平台.这意味着, ...
- ManualResetEvent 线程通信
using System; using System.Threading; namespace ConsoleApp1 { class MyThread { Thread t = null; Manu ...
- Adorner 装饰器
装饰器 Adorner 装饰器是WPF中较为常用的技术之一,也是不同于XAML的技术. 较为特殊. 特殊于装饰器全部由C#构成,不同于ControlTenmpate和Style的元素. 装饰器在某些方 ...
- PHP中implode()和explode()
1, implode()函数返回由数组元素组合成的字符串,函数语法:string implode(separator,array),separator参数可选,规定数组元素之间放置的内容,默认是空字符 ...
- DHCP应用案列
环境:centos7 需求:让员工实现0配置即可接入网络,但公司内部的若干文件服务器和打印机服务器需要使用固定的ip 部署dhcp服务很简单,首先安装dhcp,yum -y install dhcp. ...
- 基于Java软引用机制最大使用JVM堆内存并杜绝OutOfMemory
题记:说好的坚持一周两篇文章在无数琐事和自己的懒惰下没有做好,在此表达一下对自己的不满并对有严格执行力的人深表敬意!!!! -------------------------------------- ...
- dbproxy-user/pwd
dbproxy 的账号是统一的, 即连接dbproxy,连接主mysql ,连接从mysql 的账号必须一样, 为了隔离 即使用dbproxy的人感知不到mysql, 需要分离 配置文件 #dbpro ...
- PHP中SimpleXMLElement对象字符编码
最近在使用SimpleXMLElement来生成和解析XML. 由于我们使用PHP开发的这边使用UTF-8编码,而对方使用GBK编码,因此就遇到了中文字符编码问题. 后来发现,XML内部的编码与其头 ...
- 本地搭建GitLab
现在很多企业都开始使用gitLab,因为他的权限管理强大,后台项目管理也很方便.下面就介绍本地搭建方法: 为避免损失,建议在虚拟机测试.虚拟机最低配置(内存2G,cpu:2核,硬盘:20G) 1.安装 ...