【图】邻接矩阵

news2024/9/21 22:32:36

        图的存储结构分为邻接矩阵和邻接表两种,带权的图叫做网。

邻接矩阵

        邻接矩阵适合边多的图

 无向图

        两个顶点之间的连线是双向的,一个一维数组存顶点,一个二维数组存边

若有边则值为1,反之为0

        邻接矩阵需要知道点数、边数、一个二维数组存边、一个指针指向点,一个规定最多存放顶点数的值。

#define SIZE 10
class Graph
{
	int m_MaxVertex;//最大顶点个数
	int m_NumVertex;//实际顶点个数
	int m_NumEdge;//边数
	char* m_VertexArr;//存顶点
	int m_Edge[SIZE][SIZE];//存边

public:
	Graph();//构造
	~Graph();//析构
	void InsertVertex(char v);//插入点
	void InsertEdge(char v1, char v2);//在点v1和v2之间插入边
	void PrintGraph();//输出
	int GetVertexIndex(char v);//获取下标
	void DeleteEdge(char v1, char v2);//删除边
	void DeleteVertex(char v);//删除点
};

构造和析构函数

Graph::Graph()
{
	m_MaxVertex = SIZE;//设置最大的顶点数
	m_NumVertex = m_NumEdge = 0;//初始为0
	for (int i = 0; i < m_MaxVertex; i++)
	{
		for (int j = 0; j < m_MaxVertex; j++)
			m_Edge[i][j] = 0;
	}
	m_VertexArr = new char[m_MaxVertex];//m_VertexArr指向装顶点的数组
}
Graph::~Graph()
{
	if (m_VertexArr != nullptr)
	{
		delete[]m_VertexArr;
		m_VertexArr = nullptr;
	}
	m_NumEdge = m_NumVertex = 0;
}

插入顶点

如果顶点数大于最多能存的顶点数,直接返回

否则存入存顶点的数组m_VertexArr,实际顶点数m_NumVertex++

//插入顶点
void Graph::InsertVertex(char v)
{
	if (m_NumVertex >= m_MaxVertex)
	{
		return;
	}
	m_VertexArr[m_NumVertex++] = v;
}

得到一个顶点的下标

从第一个遍历到最后一个,若找到了,返回下标;若没找到,返回-1。

//得到下标
int Graph::GetVertexIndex(char v)
{
	for (int i = 0; i < m_NumVertex; i++)
	{
		if (v == m_VertexArr[i])
		{
			return i;
		}
	}
	return -1;
}

插入边

        在v1和v2两个顶点之间插入边:

首先找到两个顶点的下标;

若找到,使其存边数组中值等于1,因为是无向图,所以要m_Edge[p1][p2] = m_Edge[p2][p1]=1;

边数++

//插入边
void Graph::InsertEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -1 || p2 == -1)return;

	m_Edge[p1][p2] = m_Edge[p2][p1]=1;
	m_NumEdge++;
}

删除边

        与插入边类似。

//删边
void Graph::DeleteEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -1 || p2 == -1)return;

	m_Edge[p1][p2] = m_Edge[p2][p1] = 0;
	m_NumEdge--;
}

删除点

方法1:直接删

        这个方法比较麻烦,要将点、边数组中该点后面的数据全部往前移,如果边多不适合该方法

1.找下标,2.求相连边数,3.删点,4.删边行列(出、入)

void Graph::DeleteVertex(char v)
{
	int p = GetVertexIndex(v);//找点下标
	if (p == -1)return;

	int i = 0,j = 0;
	int delEdge = 0;//删除边的个数
	for (i = 0; i < m_NumVertex; i++)//计算与该点相连的边的个数
	{
		if (m_Edge[p][i] = 1)
			delEdge++;
	}
	for (i = p; i < m_NumVertex-1; i++)
	{
		m_VertexArr[i] = m_VertexArr[i + 1];//删顶点(把数组中后面的点往前移)
	}
	for (i = p; i < m_NumVertex-1; i++)
	{
		for (j = 0; j < m_NumVertex; j++)
		{
			m_Edge[j][i] = m_Edge[j][i + 1];//删列
		}
	}
	for (i = p; i < m_NumVertex - 1; i++)
	{
		for (j = 0; j < m_NumVertex - 1; j++)
		{
			m_Edge[i][j] = m_Edge[i + 1][j];//删行
		}
	}
	m_NumEdge -= delEdge;//更新边数
	m_NumVertex--;//更新点数
}

方法2:替换法

用最后一个顶点替换要删除的顶点,边用最后一行替换要删的,这样数组大小直接--就可删。

void Graph::DeleteVertex(char v)
{
	int p = GetVertexIndex(v);//找下标
	if (p == -1)return;

	int i = 0, j = 0;
	int delEdge = 0;//删除的边数
	for (i = 0; i < m_NumVertex; i++)//求相连的边数
	{
		if (m_Edge[p][i] = 1)
			delEdge++;
	}
	m_VertexArr[p] = m_VertexArr[m_NumVertex - 1];//要删的点替换成数组中最后一个点
	for (i = 0; i < m_NumVertex; i++)
	{
		m_Edge[i][p] = m_Edge[i][m_NumVertex - 1];//要删的边替换成数组中最后列边
	}
	for (i = 0; i < m_NumVertex - 1; i++)//注意这里点数-1
	{
		m_Edge[p][i] = m_Edge[m_NumVertex - 1][i];//要删的边替换成数组中最后行边
	}
	
	m_NumEdge -= delEdge;//更新边
	m_NumVertex--;//更新点
}

输出

void Graph::PrintGraph()
{
	int i, j;
	cout << "  ";
	for (i = 0; i < m_NumVertex; i++)
	{
		cout << m_VertexArr[i] << " ";//A B C D
	}
	cout << endl;
	for (i = 0; i < m_NumVertex; i++)
	{	
		cout << m_VertexArr[i] << " ";//竖行的ABCD
		for (j = 0; j < m_NumVertex; j++)
		{
			cout << m_Edge[i][j] << " ";//输出边
		}
		cout << endl;
	}
}

测试

int main()
{
	Graph g;
	cout << "插入ABCD顶点,在AB、AD、BC、BD、CD间插入边\n";
	g.InsertVertex('A');
	g.InsertVertex('B');
	g.InsertVertex('C');
	g.InsertVertex('D');
	g.InsertEdge('A', 'B');
	g.InsertEdge('A', 'D');
	g.InsertEdge('B', 'C');
	g.InsertEdge('B', 'D');
	g.InsertEdge('C', 'D');
	g.PrintGraph();
	cout << "删除AD间的边\n";
	g.DeleteEdge('A', 'D');
	g.PrintGraph();
	cout << "删除点B\n";
	g.DeleteVertex('B');
	g.PrintGraph();
}

        

        网的邻接矩阵中无边的为正无穷符号,可以用INT_MAX表示,其他的边数组的值为权值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/480529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM微处理器的指令集概述

ARM处理器是基于精简指令集计算机&#xff08;RISC&#xff09;原理设计的&#xff0c;指令集和相关译码机制较为简单。ARM微处理器的指令集是加载&#xff08;Load&#xff09;/存储&#xff08;Store&#xff09;型的&#xff0c;也即指令集仅能处理寄存器中的数据&#xff0…

【论文笔记】Attention和Visual Transformer

Attention和Visual Transformer Attention和Transformer为什么需要AttentionAttention机制Multi-head AttentionSelf Multi-head Attention&#xff0c;SMA TransformerVisual Transformer&#xff0c;ViT Attention和Transformer Attention机制在相当早的时间就已经被提出了&…

Word2vec原理+实战学习笔记(二)

来源&#xff1a;投稿 作者&#xff1a;阿克西 编辑&#xff1a;学姐 前篇&#xff1a;Word2vec原理实战学习笔记&#xff08;一&#xff09; 视频链接&#xff1a;https://ai.deepshare.net/detail/p_5ee62f90022ee_zFpnlHXA/6 5 对比模型&#xff08;论文Model Architectur…

锐捷(十七)锐捷单臂路由的配置

一 实验拓扑 二 实验需求 用单臂路由实现不同vlan间的通信&#xff0c;即要求vlan10的主机和vlan20的主机之间通过三层实现互访 三 实验分析 路由器的物理接口可以被划分成多个逻辑接口&#xff0c;这些被划分后的逻辑接口被形象的称为子接口。值得注意的是这些逻辑子接口不能…

Redis高级——键值对设计

1、Redis键值设计 1.1、优雅的key结构 Redis的Key虽然可以自定义&#xff0c;但最好遵循下面的几个最佳实践约定&#xff1a; 遵循基本格式&#xff1a;[业务名称]:[数据名]:[id]长度不超过44字节不包含特殊字符 例如&#xff1a;我们的登录业务&#xff0c;保存用户信息&a…

AIGC迈向通用人工智能时代

一、AIGC“起飞”的背后 2023年1月30日&#xff0c;AIGC概念股突飞猛涨。一时间&#xff0c;AIGC再次站上风口浪尖。 AIGC&#xff08;AI Generated Content&#xff09;是指利用人工智能技术来生成内容&#xff0c;被认为是继UGC、PGC之后的新型内容生产方式&#xff0c;常见…

哈希的应用 -- 布隆过滤器与海量数据处理

文章目录 布隆过滤器概念布隆过滤器设计思路布隆过滤器的应用布隆过滤器模拟实现布隆过滤器的基本框架布隆过滤器的插入布隆过滤器的探测布隆过滤器的删除 布隆过滤器优点布隆过滤器缺陷布隆过滤器模拟实现代码及测试代码海量数据处理哈希切割哈希切分 布隆过滤器概念 布隆过滤…

【机器学习】HOG+SVM实现行人检测

文章目录 一、准备工作1. 下载数据集2. 解压数据集 二、HOG特征简介1. 梯度&#xff08;Gradient&#xff09;2. 格子&#xff08;Cell&#xff09;3. 块归一化&#xff08;Block Normalization&#xff09;4. HOG特征&#xff08;HOG Feature&#xff09;5. 使用skimage.featu…

“五一”假期消防安全知识要牢记之消防安全知识答题活动

“五一”期间&#xff0c;容易出现哪些安全隐患&#xff0c;生产生活中要注意哪些安全事项&#xff0c;一起来看&#xff01; 森林防火&#xff1a; 1.禁止将火柴、汽油等易燃物带入山林&#xff0c;禁止乱扔火种。 2.景区管理单位要加强防火巡逻&#xff0c;禁止野外火源&am…

smbms项目搭建

目录 1.搭建一个maven web项目 2.配置Tomcat 3.测试项目是否能够跑起来 4.导入项目中会遇到的Jar包 5.项目结构搭建 6.项目实体类搭建 7.编写基础公共类 1.数据库配置文件 2.编写数据库的公共类 3.编写字符编码过滤器 3.1web配置注册 4.导入静态资源 1.搭建一个maven web项目 …

C++前置声明的理解

知识补充 在C/C中引入一个头文件时&#xff0c;在编译器预处理的时候会将引入头文件的地方简单替换成头文件的内容。这样做的后果是很容易引起头文件的重复引用。所以我们在编写头文件是一般有以下规定来防止头文件被重复包含。 MyWidget.h #ifndef MyWidget_H_ #define MyWi…

实验四、彩色图像处理

实验目的 使用MatLab软件对图像进行彩色处理&#xff0c;熟悉使用MatLab软件进行图像彩色处理的有关方法&#xff0c;并体会到图像彩色处理技术以及对图像处理的效果。 作业1&#xff1a;生成一副256*256的RGB图像&#xff0c;使得该图像左上角为黄色或者青色&#xff0c;左下…

day04_基本数据类型丶变量丶类型转换

前置知识 计算机世界中只有二进制。那么在计算机中存储和运算的所有数据都要转为二进制。包括数字、字符、图片、声音、视频等。 进制 进制也就是进位计数制&#xff0c;是人为定义的带进位的计数方法 。不同的进制可以按照一定的规则进行转换。 进制的分类 十进制&#x…

Seurat -- Perform linear dimensional reduction

brief 什么是线性降维&#xff1f; 这里是一个很形象的网页演示&#xff0c;其中包括了一个视频链接。 这里是如何用R 包psych做线性降维的演示&#xff0c;其中也有原理的简述。 为什么要做线性降维&#xff1f; 因为下一步的聚类分析需要这里的降维结果作为输入。降维做的好…

14-3-进程间通信-消息队列

前面提到的管道pipe和fifo是半双工的&#xff0c;在某些场景不能发挥作用&#xff1b; 接下来描述的是消息队列&#xff08;一种全双工的通信方式&#xff09;&#xff1b; 比如消息队列可以实现两个进程互发消息&#xff08;不像管道&#xff0c;只能1个进程发消息&#xff…

vulnhub靶机Misdirection

环境准备 下载链接&#xff1a;https://download.vulnhub.com/misdirection/Misdirection.zip 解压后双击ovf文件导入虚拟机 网络&#xff1a;DHCP、NAT、192.168.100.0/24网段 信息收集 主机发现 192.168.100.133是新增的ip 端口扫描 发现开放了以上端口&#xff0c;继续…

【Java笔试强训 28】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、选择题 二、编程题 &#x1f525;猴子分桃…

【Python入门】Python搭建编程环境-安装Python3解释器(内含Windows版本、MacOS版本、Linux版本)

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于Python零基础入门系列&#xff0c;本专栏主要内容为Python基础语法、判断、循环语句、函…

与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!!

与其焦虑被 AI 取代或猜测前端是否已死, 不如看看 vertical-align 扎实你的基础!!! vertical-align 设置 display 值为 inline, inline-block 和 table-cell 的元素竖直对齐方式. 从 line-height: normal 究竟是多高说起 我们先来看一段代码, 分析一下为什么第二行的行高, 也就…