【图论入门】图的存储

news2024/9/20 18:38:06

1.邻接矩阵

邻接矩阵是图论中用于表示图(Graph)结构的一种重要数据结构,特别适用于表示顶点之间连接关系的图形。在计算机科学和数学领域,它被广泛应用来编码无向图和有向图的信息。

特点:

1、无向图的邻接矩阵是对称的,且主对角线元素全为0(因为自己到自己没有边)

2、顶点i的度=第i行(列)中1的个数。

3、完全图的邻接矩阵中,主对角元素为0,其余全为1.

有向图的邻接矩阵

在图论中,网(Network)是指带有权重的图,其中边或弧可以具有非零的权值,通常代表距离、成本或其他度量。对于这样的带权图,其邻接矩阵的表示会包含每个顶点对之间的权值信息。

网的邻接矩阵 是一个 n×n 的矩阵 A,对于有向网:

  • 矩阵中的元素 (A[i][j]) 表示从顶点 i 到顶点 j 的有向边的权值。
    • 如果没有从顶点 i 到顶点 j 的边,则 (A[i][j]) 可以被赋值为无穷大(一般用极大整数表示)或者一个特殊值(如 null 或 -1),表示不存在路径或无法到达。

对于无向网:

  • 矩阵仍然是对称的,即如果顶点 i 和顶点 j 之间存在一条无向边且带有一个权值 w,那么 (A[i][j] = A[j][i] = w)。

举例来说,假设有一个无向网,其中有三条边连接着三个顶点,并且边的权值分别为:(顶点1, 顶点2) 权重为3,(顶点1, 顶点3) 权重为5,(顶点2, 顶点3) 权重为1,则对应的邻接矩阵可能是:

| 0   3   5 |
| 3   0   1 |
| 5   1   0 |

通过邻接矩阵,我们可以直观地看出任意两点间的直接连通性和权值大小,便于进行诸如最短路径计算等图算法的操作。

优缺点:

邻接矩阵表示法的优缺点

优点:

  • 直观、简单、好理解
  • 方便检查任意一对顶点间是否存在边
  • 方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
  • 方便计算任一顶点的“度”。

缺点:

  • 不便于增加和删除顶点
  • 浪费空间——存稀疏图(点很多而边很少)有大量无效元素
  • 对稠密图(特别是完全图)还是很合算的
  • 浪费时间——统计稀疏图中一共有多少条边
#include<iostream>
using namespace std;
 
#define INF 65535 //表示无穷大,其他合理的值也可
#define MaxVerNum  1000 //定义顶点最大数量
 
typedef int cellType; //定义邻接矩阵元素数据类型,即权值的数据类型
 
//定义图的类型分别为无向图,无向带权图,有向图,有向带权图 
typedef enum{
	UDG,UDN,DG,DN
}GraphKind; 
 
 
class GraphAdjMatrix
{
private: 
	int VerNum;//顶点数量 
	int ArcNum;//边数量 
	GraphKind gKind; //图类型 
	cellType** AdjMatrix;//邻接矩阵 
public:
	GraphAdjMatrix(); 
	void createGraph();//构建图	
	void GraphSet(int VerNum,int ArcNum,int kind);//图属性设置 
	int getVerNum() {return VerNum;}
	int getArcNum()	{return ArcNum;}
	GraphKind geyGraphKind() {return gKind;};
	void setMatrix(int i,int j,int w) ; //邻接矩阵设置 
	void printMatrix();//打印邻接矩阵 
};
 
GraphAdjMatrix::GraphAdjMatrix()//构造函数 
{
	AdjMatrix  = new cellType*[MaxVerNum];
	for(int i=0;i<MaxVerNum;i++)// 为邻接矩阵分配内存 
		AdjMatrix[i] = new cellType[MaxVerNum];
}
 
void GraphAdjMatrix::setMatrix(int i,int j,int w) 
{	
	AdjMatrix[i][j]=w; 
	if(gKind==UDG||gKind==UDN) //如果是无向图,则设置对称位置权重 
		AdjMatrix[j][i]=w;
};
 
void GraphAdjMatrix::createGraph()
{
	int vn,an,k;//分别代表顶点数量,边数量,以及图类型 
	cout<<"输入顶点数量,边数量,图类型用空格隔开"<<endl;
	cout<<"0-无向无权图 1-无向带权图 2-有向无权图 3-有向带权图"<<endl; 
	cin>>vn>>an>>k;
	VerNum = vn;
	ArcNum = an;
	gKind = (GraphKind)k;
	int i,j,w;
	
	//初始化邻接矩阵 
	for(int i=1;i<=vn;i++)
	{
		for(int j=1;j<=vn;j++)
		{
			AdjMatrix[i][j]=INF;
		}
	}
	/*无向图,无向带权图,有向图,有向带权图 */
	GraphKind gk;
	
	while(an--)
	{
		if (k == UDG || k == DG)//如果是无权图,则将边权重设为1 
		{
			cin>>i>>j;
			AdjMatrix[i][j]=1;
			if (k==UDG)//如果是无向图,对称位置设置权重 
				AdjMatrix[j][i]=1;
		}
		else
		{
			cin>>i>>j>>w;
			AdjMatrix[i][j]=w;
			if (k == UDN)//如果是无向图,对称位置设置权重 
				AdjMatrix[j][i]=w;
		}
	}
}
 
void GraphAdjMatrix::printMatrix()
{
	for(int i=1;i<=VerNum;i++)
	{
		for(int j=1;j<=VerNum;j++)
		{
			if (AdjMatrix[i][j]==INF)
				cout<<"*"<<"\t";
			else
				cout<<AdjMatrix[i][j]<<"\t";
		}
		cout<<endl;
	}
}
 
int main()
{
	GraphAdjMatrix cg;
	cg.createGraph();
	cg.printMatrix();
	return 0;
}

2.邻接表

这里简单介绍算法题中常用的建表方式(自己使用的)

在理解邻接表时,先入为主地按照了尾插法去思考,所以总是对不上。实际上最重要的是它使用的是头插法。
因为抽象思考能力很差(没错就是这么菜),这里用一个形象的方式模拟观察一下。

add函数:

void add(int a, int b, int c)  // 添加一条边a->b,距离为c
{
  e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
  // e = dst, ne = h(from), h(from) = idx
}

3.链式前向星(具体注释在代码里)

为了更好的节约空间,使用静态数组模拟邻接表,使得空间效率变高,不造成任何的浪费

下面代码用addedge()函数存储一条新的边

1.idx 记录边的序号

2、邻接表包括四个数组:e、w、ne、h

e[idx] = b:表示第 idx 条边通向 b 点
w[idx] = c:表示第 idx 条边的权值为 c
ne[idx] = h[a]:表示以a为起点的第 idx 条边的下一条边为 h[a](-1表示无边)
h[a] = idx++:表示点 a 的上一条边为 idx

其中 h 数组的大小是点数,其他三个数组的大小都是边数。

代码实现:

// 加入有向边 (a, b),权值为 c
void add(int a, int b, int c)
{
     e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

访问操作

// 访问从x出发的所有边
for (int i = h[x]; ~i; i = ne[i])
{
    int y = e[i], z = w[i];
    // 找到了一条有向边 (x, y),权值为z
}

4.拓扑排序

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
const int N = 1e5 + 10;
int e[N],ne[N],h[N],idx,d[N],n,m,top[N],cnt = 1;
// e,ne,h,idx 邻接表模板
// d 代表每个元素的入度
// top是拓扑排序的序列,cnt代表top中有多少个元素
void add(int a,int b)
{
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx ++;
}
bool topsort()
{
    queue<int> q;
    int t;
    for(int i = 1;i <= n; ++i)// 将所有入度为0的点加入队列
        if(d[i] == 0) q.push(i);
    while(q.size())
    {
        t = q.front();//每次取出队列的首部
        top[cnt] = t;//加入到 拓扑序列中
        cnt ++; // 序列中的元素 ++
        q.pop();
        for(int i = h[t];i != -1; i = ne[i])
        {
            // 遍历 t 点的出边
            int j = e[i];
            d[j] --;// j 的入度 --
            if(d[j] == 0) q.push(j); //如果 j 入度为0,加入队列当中
        }
    }
    return cnt - 1 == n;

}
int main()
{
    int a,b;
    cin >> n >> m;
    memset(h,-1,sizeof h);
    while(m--)
    {
        cin >> a >> b;
        add(a,b);
        d[b] ++;// a -> b , b的入度++
    }
    if(topsort() == 0) cout << "-1";
    else 
    {
        for(int i = 1;i <= n; ++i)
        {
            cout << top[i] <<" ";
        }
    }
    return 0;
}

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

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

相关文章

Java:时区的用法

文章目录 ZoneId常见用法 ZonedDateTime常见方法 代码 黑马学习笔记 ZoneId 常见用法 ZonedDateTime 常见方法 代码 package NewTime;import java.time.Clock; import java.time.ZoneId; import java.time.ZonedDateTime;/*** Author: ggdpzhk* CreateTime: 2024-08-31*/ pu…

09:Logic软件原理图信号连通

原理图信号连通 快捷键&#xff1a;F2 2.添加网络名称

【React】为什么Hooks不能出现在判断中

前言 在 React 中&#xff0c;Hooks 不能写在条件语句中&#xff0c;如下面这段代码点击button后则会报错。 import { useEffect, useState } from "react"export default () > {const [count, setCount] useState(0)if (count > 0) {useEffect(() > {co…

4-4 初始化引导程序

基本原理的讲解 在loader所需要做的事情&#xff0c; 1 他这个检测内存的容量&#xff0c;我想知道是怎么做的。 2 然后就是模式的切换。 3 然后就是加载操作系统&#xff0c;并跳转到操作系统执行。 这是 他的总体的逻辑。 首先是加载 512 字节。 所以这512 字节的主要任务…

【Kubernetes部署篇】二进制搭建K8s高可用集群1.26.15版本

文章目录 一、服务器环境信息及部署规划1、K8S服务器信息及网段规划2、服务器部署架构规划3、组件版本信息 二、初始化环境操作1、关闭防火墙2、配置本地域名解析3、配置服务器时间保持一致4、禁用swap交换分区(K8S强制要求禁用)5、配置主机之间无密码登录6、修改Linux内核参数…

springboot 医院挂号系统 ---附源码91789

目录 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 医院挂号系统系统分析 2.1 可行性分析 2.2 系统功能分析 2.3 系统用例分析 2.4 系统流程分析 图2-5业务流程图 2.5本章小结 3 医院挂号系统总体设计 3.1 系统功能模块设计 3.2 数据库设计 3.4本章…

Python读取CSV文件的几种方法!

1、使用 csv 模块 首先&#xff0c;你需要导入csv模块&#xff1a; import csv接下来&#xff0c;你可以使用csv.reader()函数来读取CSV文件。假设你的CSV文件名为data.csv&#xff0c;它的内容如下&#xff1a; Name, Age, Salary John, 25, 5000 Alice, 30, 6000 Bob, 35,…

书生浦语实训营-InternVL 多模态模型部署微调实践

1.什么是InternVL InternVL 是一种用于多模态任务的深度学习模型&#xff0c;旨在处理和理解多种类型的数据输入&#xff0c;如图像和文本。它结合了视觉和语言模型&#xff0c;能够执行复杂的跨模态任务&#xff0c;比如图文匹配、图像描述生成等。 2.InternVL模型介绍 对于…

【自由能系列(初级)】生命负熵——熵增原理与生命秩序的对抗

【通俗理解】生命负熵——熵增原理与生命秩序的对抗 关键词提炼 #生命负熵 #熵增原理 #生命秩序 #薛定谔方程 #熵减过程 #热力学第二定律 #信息熵 #生命系统建模 #负熵流 #熵平衡 第一节&#xff1a;生命负熵的类比与核心概念 1.1 生命负熵的类比 生命负熵可以被视为生命系…

如何打造免费体育馆场地预约系统?php vue技术实现,简易操作指南

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Unity(2022.3.41LTS) - 脚本

目录 零.简介 一、脚本的基本概念 二、脚本的创建和使用 三、脚本的编程基础 四、与 Unity 引擎的交互 五、重要的类介绍 六、事件函数介绍 七、事件函数的执行顺序 八、脚本的优化和调试 零.简介 在 Unity 中&#xff0c;脚本是实现游戏逻辑和交互的重要组成部分。 …

后台框架-统一数据格式2

在上一篇中&#xff0c;当在Controller类中需要返回统一格式的数据时&#xff0c;需要实例化一个R&#xff0c;有时候觉得还是不够简洁&#xff0c;那有没有一种方法Controller中直接返回对象&#xff0c;但是返回的对象统一保存到如下格式的data中&#xff1f; ResponseBody…

P9343 一曲新词酒一杯

import java.util.Scanner;public class Main {static int fun(Scanner sc) {int n, m;int res -1;int k 0;n sc.nextInt();// n个杯子m sc.nextInt();// m次操作boolean[] a new boolean[n];boolean[] v new boolean[n];for (int i 0; i < m; i) {int o, x;o sc.ne…

科研绘图系列:R语言组合图形绘图

介绍 柱状图、箱线图和棒棒图组合 加载R包 # Library library(ggplot2) library(dplyr) library(forcats)读取数据 data <- data.frame(name=c("north","south","south-east","north-west","south-west","north…

【Pytorch】一文向您详尽解析 with torch.no_grad(): 的高效用法

【Pytorch】一文向您详尽解析 with torch.no_grad(): 的高效用法 下滑即可查看博客内容 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我静心耕耘深度学习领域、真诚分享知识与智慧的小天地&#xff01;&#x1f387; &#x1f393; 博主简介&#xff1a;985高…

机器学习与人工智能在未来建筑行业的应用:项目案例与分析

作者主页: 知孤云出岫 目录 作者主页:前言1. 项目背景1.1 行业挑战1.2 人工智能与机器学习的引入 2. 项目案例&#xff1a;智能建筑能耗管理系统2.1 项目介绍2.2 技术实现2.2.1 数据采集与预处理2.2.2 能耗预测模型构建2.2.3 控制策略优化 2.3 实施效果 3. 其他应用案例3.1 建…

产品经理角度分析:朋友圈点赞与评论仅共同好友可见

你有没有在刷朋友圈时&#xff0c;看到某位朋友发了条状态&#xff0c;下面一堆点赞和评论&#xff0c;然后他自己来个“统一回复下&#xff0c;感谢大家”&#xff1f; 这种现象就像是在朋友圈里开了个小型新闻发布会&#xff0c;大家在台下疯狂举手&#xff0c;结果发言人最后…

揭秘排行榜系统:如何在高并发场景下实现高效更新!

大家好,我是你们的技术分享伙伴小米!今天我们来聊聊一个非常有趣的话题——如何设计一个排行榜。在这个互联网时代,无论是游戏、学习平台,还是各种社交应用,排行榜都是用户互动和竞争的核心功能之一。而如何设计一个高效、实时更新的排行榜,是一个充满挑战性的问题。今天…

约瑟夫环和一元多项式

约瑟夫环 一、问题描述 假设有 n 个人围成一圈&#xff0c;从第一个人开始报数&#xff0c;报数到 m 的人将被淘汰出圈&#xff0c;然后从下一个人开始继续从 1 报数&#xff0c;如此重复&#xff0c;直到最后只剩下一个人。求最后剩下的这个人的编号。 二、问题分析 可…

最新Vmware17的WIn10虚拟机开箱即用,免安装

这篇文章分享的Vmware安装Win10的教程&#xff0c;如过有些懒得装Win10的同学可以会直接使用我的WIn10镜像压缩包打开即可 Win10镜像压缩包下载 tips&#xff1a;⬆️⬆️包含Vmware17安装包 使用方法&#xff0c;打开Vmware