【图】邻接表

news2024/9/23 12:14:29

目录

无向图的邻接表

 链表(存相邻顶点下标)的类

数组里放的顶点

邻接表(操作)

构造和析构(创建销毁邻接表)

插入顶点

插入边

获取下标

插v1、v2之间的边

删除顶点

删除边

输出:

其他图邻接表


         

        邻接表用一个一维数组存图的顶点和指针,指针指向一个链表,链表里存放与当前顶点相连的顶点在数组中的下标。如下图(无向图邻接表):

无向图的邻接表

 链表(存相邻顶点下标)的类

class Edge
{
public:
	Edge() :m_next(nullptr) {}
	Edge(int v) :m_destindex(v), m_next(nullptr) {}
	int m_destindex;//下标
	Edge* m_next;//下一个邻接顶点的结点
};

数组里放的顶点

class Vertex
{
public:
	Vertex() :m_list(nullptr) {}
	Vertex(int v) :m_VerValue(v), m_list(nullptr) {}
	char m_VerValue;//顶点值
	Edge* m_list;//指针指向邻接顶点的链表
};

邻接表(操作)

插入顶点,插入边,删除顶点,删除边,获取顶点在数组中的下标(前面的操作需要用)

#define SIZE 10
class GraphLink
{
public:
	GraphLink();
	~GraphLink();
	void InsertVertex(char v);//插顶点
	void InsertEdge(char v1, char v2);//插边
	void PrintGraph();//打印
	void DelVertex(char v);//删顶点
	void DelEdge(char v1, char v2);//删边
	int GetVertexIndex(char v);//获取顶点下标
private:
	int m_MaxVertex;//最多结点数
	int m_NumVertex;//当前结点数
	int m_NumEdge;//边数
	Vertex* m_VerArr;//存顶点的数组(指针指向数组头)
};

构造和析构(创建销毁邻接表)

创建:给m_VerArr指针new最大顶点数m_MaxVertex个顶点Vertex大小的空间;

销毁:释放指向数组起始的指针的空间。

GraphLink::GraphLink() :m_MaxVertex(SIZE), m_NumVertex(0), m_NumEdge(0)
{
	m_VerArr = new Vertex[m_MaxVertex];
}
GraphLink::~GraphLink()
{
	if (m_VerArr != nullptr)
	{
		delete[]m_VerArr;
		m_VerArr = nullptr;
	}
}

插入顶点

        首先确定顶点数(不能超过设定的最大顶点数)。

        若可插:将顶点值赋到数组中最后一个位置m_VerArr[m_NumVertex],顶点个数++。

void GraphLink::InsertVertex(char v)
{
	if (m_NumVertex >= m_MaxVertex)return;
	m_VerArr[m_NumVertex++].m_VerValue = v;
}

插入边

插入顶点v1到顶点v2的边时,由于链表中记录的是顶点的下标,所有首先需要有一个获取下标的函数:

获取下标

        遍历数组记录下标,找到顶点即可找到下标返回,若没找到:返回-1。

int GraphLink::GetVertexIndex(char c)
{
	for (int i = 0; i < m_NumVertex; i++)
	{
		if (m_VerArr[i].m_VerValue == c)
			return i;
	}
	return -1;
}

插v1、v2之间的边

        注意:无向图插一条边需要改两个表。

获取下标后,插入方法与链表头插相同。

void GraphLink::InsertEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -2 || p2 == -1)return;

	//v1->v2 既是在v1的边链表中插入值为p2的边节点
	Edge* edge = new Edge(p2);
	edge->m_next = m_VerArr[p1].m_list;
	m_VerArr[p1].m_list = edge;
	//v2->v1
	edge = new Edge(p1);
	edge->m_next = m_VerArr[p2].m_list;
	m_VerArr[p2].m_list = edge;

	m_NumEdge++;
}

删除顶点

用覆盖删除的方法:数组最后一个顶点覆盖要删的,并修改链表内受影响下标的值。

void GraphLink::DelVertex(char v)
{
	int p = GetVertexIndex(v);
	if (p == -1)return;
	Edge* pp = m_VerArr[p].m_list;
	char destvalue;
	while (pp)
	{
		destvalue = m_VerArr[pp->m_destindex].m_VerValue;
		DelEdge(v, destvalue);
		pp = m_VerArr[p].m_list;
	}
	//覆盖
	m_NumVertex--;
	m_VerArr[p].m_VerValue = m_VerArr[m_NumVertex--].m_VerValue;
	//修改
	Edge* q = nullptr;
	pp = m_VerArr[p].m_list;
	while (pp != nullptr)
	{
		int k = pp->m_destindex;
		q = m_VerArr[k].m_list;
		while (q)
		{
			if (q->m_destindex == m_NumVertex)
			{
				q->m_destindex = p;
				break;
			}
			q = q->m_next;
		}
		pp = pp->m_next;
	}
}

删除边

void GraphLink::DelEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -2 || p2 == -1)return;
	//在p1里面删p2
	Edge* pf = m_VerArr[p1].m_list;
	if (m_VerArr[p1].m_list->m_destindex == p2)
	{
		m_VerArr[p1].m_list = m_VerArr[p1].m_list->m_next;
		delete pf;
		pf = nullptr;
	}
	else
	{
		while (pf->m_next->m_destindex != p2 && pf != nullptr)
		{
			pf = pf->m_next;
		}
		if (pf == nullptr)return;

		Edge* p = pf->m_next;
		pf->m_next = p->m_next;
		delete p;
		p = nullptr;
	}
	//v2->v1
	pf = m_VerArr[p2].m_list;
	if (m_VerArr[p2].m_list->m_destindex == p1)
	{
		m_VerArr[p2].m_list = m_VerArr[p2].m_list->m_next;
		delete pf;
		pf = nullptr;
	}
	else
	{
		while (pf->m_next->m_destindex != p1 && pf != nullptr)
		{
			pf = pf->m_next;
		}
		if (pf == nullptr)return;

		Edge* p = pf->m_next;
		pf->m_next = p->m_next;
		delete p;
		p = nullptr;
	}

	m_NumEdge--;
}

输出:


void GraphLink::PrintGraph()
{
	Edge* p = nullptr;
	for (int i = 0; i < m_NumVertex; i++)
	{
		cout << i << " " << m_VerArr[i].m_VerValue << " ";
		p = m_VerArr[i].m_list;
		while (p)
		{
			cout << p->m_destindex << "->";
			p = p->m_next;
		}
		cout << "nul" << endl;
	}
	cout << endl;
}

其他图邻接表

        有向图注意边的数量修改,网需要在链表结点中加上存边权值的部分。

 网结构如下:

 

 

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

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

相关文章

多种采购方式下,数智化招采系统解决方案(实例)

广发证券成立于1991年&#xff0c;是国内首批综合类证券公司&#xff0c;先后于2010年和2015年在深圳证券交易所及香港联合交易所主板上市。 多年来&#xff0c;广发证券在竞争激烈、复杂多变的行业环境中努力开拓、锐意进取&#xff0c;以卓越的经营业绩、持续完善的全面风险…

Node.js对ES6 及更高版本的支持

目录 1、简介 2、默认情况下什么特性随着 Node.js 一起发布&#xff1f; 3、有哪些特性在开发中&#xff1f; 4、移除这个标记&#xff08;--harmony&#xff09;吗 5、Node.js 对应 V8 引擎 1、简介 Node.js 是针对 V8 引擎构建的。通过与此引擎的最新版本保持同步&…

PMP课堂模拟题目及解析(第5期)

41. 项目的混凝土供应商通知项目经理&#xff0c;材料将比预定时间晚三个星期交付。项目经理更新了进度计划并通知项目团队。在这种情况下&#xff0c;哪种合同类型承担的风 险最小&#xff1f; A. 总价加激励费用合同。 B. 总价加经济价格调整合同。 C. 工料合同。 D. 固…

matlab学习笔记

一、序言 1. 图像的输入输出和显示 fimread("test.png"); frgb2gray(f);%rgb图像转化为灰度图像 imshow(f); imwrite(f,"result.jpg","quality",50);%50代表jpg形式压缩质量0-1002. matlab支持的四种图像类别 灰度级图像(Gray-scale images) …

类和对象【C++】【中篇】

目录 一、类的6个默认成员函数 1、构造函数 2、析构函数 3、拷贝构造函数 4、赋值重载函数 二、赋值运算符重载 一、类的6个默认成员函数 注意&#xff1a;默认成员函数不能在类外面定义成全局函数。因为类里没有的话会自动生成&#xff0c;就会产生冲突。 1、构造函数…

k8s采用ansible安装

一、准备工作 测试服务器 服务器配置进程功能备注192.168.0.189CPU:4核 内存32Gansibleansible一键安装k8s192.168.0.141CPU&#xff1a;12核 内存&#xff1a;10Gdocker&#xff0c;kube-apiserver&#xff0c;etcd&#xff0c;kube-scheduler&#xff0c;kube-controller-m…

产品经理 - 原型图设计软件

原型图设计软件哪个好用&#xff1f;6款好用软件推荐&#xff01; - 知乎 摩客, 墨刀 2014 即时设计是一款支持在线协作的专业级 UI 设计工具&#xff0c;用户数已突破230万&#xff1b; 2021年 5,000万(美元) 国外 axure 老牌 如果有进一步模拟的必要&#xff0c;再换用Ad…

JetPack之lifecycle原理分析

Lifecycle是什么 Lifecycle可以有效的避免内存泄漏和解决android生命周期的常见难题Livecycle 是一个表示android生命周期及状态的对象LivecycleOwner 用于连接有生命周期的对象&#xff0c;如activity,fragmentLivecycleObserver 用于观察查LifecycleOwnerLifecycle框架使用观…

关于SSL证书有效期缩短,看这一篇就够了

在TLS/SSL证书有效期不断被缩短的大趋势下&#xff0c;我们在前文和大家聊了聊企业面临的困境、应对策略及证书自动化管理&#xff0c;今天想和大家继续探讨的是TLS/SSL证书自动化管理切实可行的解决方案。 01 自动化证书管理的重要性 TLS/SSL证书是保障网络连接安全的重要手…

图片位深度以及转换办法

位图文件的格式&#xff1a; ① 位图文件头&#xff0c;所用结构体&#xff1a;BITMAPFILEHEADER&#xff0c;占14个字节 ② 位图信息头&#xff0c;所用结构体&#xff1a;BITMAPINFOHEADER&#xff0c;占40个字节 ③ 颜色表项&#xff0c;所用结构体&#xff1a;RGBQUAD&…

Qt5.14版本通用环境配置安装——最详细教学(看不懂,你怪我)

✨✨✨大家好&#xff0c;我是会飞的鱼-blog&#xff0c;今天我来给大家介绍一下Qt5.14.1安装&#xff0c;有不足之处&#xff0c;请大家多多指教。感谢大家支持&#xff01;&#xff01;&#xff01; 目录 前言 安装文件下载&#xff1a; 安装&#xff1a; 设置 QtCreator…

测试相关记录

1、提测计划、需求拆分、颗粒度 2、线上bug回顾 3、提测流水线 4、测试业绩合同指定

6.2.4图的基本操作 6.3.1图的广度优先遍历 6.3.2图的深度优先遍历

6.2.4图的基本操作 考研里面只考邻接矩阵和邻接表的存储结构 思想较为简单见video 重点理解时间复杂度的遍历原理 6.3.1图的广度优先遍历&#xff08;BFS&#xff09;&#xff08;Breadth first traversal&#xff09; 我们从树的广度优先遍历入手去看图的广度优先遍历的思想 …

【Python入门知识】NumPy 中的随机数及ufuncs函数

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 什么是随机数&#xff1f; 随机数并不意味着每次都有不同的数字。随机意味着无法在逻辑上预测的事物。 伪随机和真随机 计算机在程序上工作&#xff0c;程序是权威的指令集。 因此&#xff0c;这意味着必须有某种算法来…

2路 QSFP,40G 光纤的数据实时采集(5GByte/s 带宽)板卡设计原理图 -PCIE732

板卡概述 PCIE732 是一款基于 PCIE 总线架构的高性能数据传输卡&#xff0c;板卡具有 1 个 PCIex8 主机接口、2 个 QSFP40G 光纤接口&#xff0c;可以实现 2 路 QSFP 40G 光纤的数据实时采集、传输。板卡采用 Xilinx 的高性 能 Kintex UltraScale 系列 FPGA 作为实时处理器…

【鲁棒优化、无功优化】两阶段鲁棒优化的主动配电网动态无功优化【IEEE33节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网曝快手在离职证明上写:如需背调,只能通过公司指定邮箱,其他渠道均不认可!如何捍卫自己的权益?...

许多公司都喜欢用离职证明拿捏打工人&#xff0c;最近有网友曝光快手在离职证明上做文章&#xff0c;在离职证明上写&#xff1a;如需背调&#xff0c;只能通过公司指定邮箱xxxxkuaishou.com&#xff0c;其他渠道均不认可&#xff01; 楼主问&#xff1a;这种情况如何捍卫自己的…

camunda脚本如何使用

一、camunda脚本有什么用途 在Camunda中&#xff0c;脚本是一种灵活的方式&#xff0c;可以用于在流程定义和表单中编写自定义逻辑。使用脚本&#xff0c;您可以编写JavaScript、Groovy、Python、Ruby等脚本语言中的代码&#xff0c;以实现各种功能。 以下是Camunda脚本的一些…

Shell脚本快速入门

Shell脚本快速入门 1 Hello World2 Shell 变量3 Shell 传递参数4 Shell 基本运算符5 Shell echo命令5 Shell printf 命令6 Shell test 命令7 Shell 流程控制8 Shell 函数9 Shell 输入/输出重定向10 Shell 文件包含参考 1 Hello World 编写脚本文件 test.sh #!/bin/bash echo …

用思科和华为的设备分别完成【单臂路由】的配置

一 什么是单臂路由&#xff1a; 单臂路由&#xff08;router-on-a-stick&#xff09;是指在路由器的一个接口上通过配置子接口&#xff08;或“逻辑接口”&#xff0c;并不存在真正的物理接口&#xff09;的方式&#xff0c;实现原来相互隔离的不同VLAN&#xff08;虚拟…