有向图和无向图的数组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 ...
随机推荐
- 在 LINQ to Entities 查询中无法构造实体或复杂类型“Mvc_MusicShop_diy.Models.Order”
错误代码: var orders = db.Orders.Where(o => o.UserId == userid).Select(c => new Order { OrderI ...
- [Erlang15]“hello world”与<<”hello world”>>的具体区别是什么?
参见 :http://learnyousomeerlang.com/buckets-of-sockets 为了加深理解,自译如下,若理解有误或更好的建议,请帮忙指出, :) Buckets of So ...
- asp.net(mvc) 框架
1.NFine mvc+ef 2.Grove orm架构 3.NHibernate orm 4.NBear 5.petshop 6.Membership 7.Brnshop 网上商城 8.cms快速开 ...
- 二十一、Node.js-EJS 模块引擎
初识 EJS 模块引擎 我们学的 EJS 是后台模板,可以把我们数据库和文件读取的数据显示到 Html 页面上面.它是一个第三方模块,需要通过 npm 安装https://www.npmjs.com/ ...
- fatal: Authentication failed for又不弹出用户名和密码 解决办法
各位,如果能弹出来,一定是你账号密码搞错了,就别继续看了. image.png 切换命令行: image.png 依然报错, 说到这个问题,又可以长篇大论了, 我使用的是tortoisegit ...
- jquery源码解析:jQuery静态属性对象support详解
jQuery.support是用功能检测的方法来检测浏览器是否支持某些功能.针对jQuery内部使用. 我们先来看一些源码: jQuery.support = (function( support ) ...
- 【转】【C++专题】C++ sizeof 使用规则及陷阱分析
提示:下文例子都经过Visual C++ 6.0验证,平台为win32 Windows. 一.什么是sizeof 首先看一下sizeof在msdn上的定义: The sizeof keyword gi ...
- Python开发转盘小游戏
Python开发转盘小游戏 Python 一 原理分析 Python开发一个图形界面 有12个选项和2个功能键 确定每个按钮的位置 每个按钮的间隔相同 点击开始时转动,当前选项的背景颜色为红色,其他 ...
- JAVA数据结构--优先队列(堆实现)
优先队列(堆)的定义 堆(英语:Heap)是计算机科学中一类特殊的数据结构的统称.堆通常是一个可以被看做一棵树的数组对象.在队列中,调度程序反复提取队列中第一个作业并运行,因为实际情况中某些时间较短的 ...
- Go语言命名
Go语言关键字 1.Go语言有25个关键字 2.关键字用途 var :用于变量的声明const :用于常量的声明type :用于声明类型func :用于声明函数和方法package :用于声明包文件i ...