数据结构-----图(graph)的储存和创建

news2024/11/18 15:32:49

目录

前言

图的储存结构

1.邻接矩阵

无向图的邻接矩阵

 有向图的邻接矩阵

网(赋权图)的邻接矩阵

 代码表示

2.邻接表

无向图的邻接表

有向图的邻接表

代码表示

3.邻接矩阵和邻接表对比

邻接矩阵

邻接表

图的创建

1.邻接矩阵创建图(网)

 2.邻接表创建图(网)


前言

        上一期我们学习了图的基础知识(链接:数据结构-----图(Graph)论必知必会知识-CSDN博客),这一期我们就学习怎么去储存图,和创建一个图,下面就一起来看看。

图的储存结构

1.邻接矩阵

邻接矩阵是图的矩阵表示,借助它可以方便地存储图的结构,用线性代数的方法研究图的问题。 如果一个图有 n 个顶点,其邻接矩阵 W 为 ntimes n 的矩阵,矩阵元素 w_ {ij} 表示边 (i,j) 的权重。 如果两个顶点之间没有边连接,则在邻接矩阵中对应的元素为0。

一个图G有n个顶点,就需要nxn矩阵来去表示。 

无向图的邻接矩阵

无向图的邻接矩阵特点:

  • 主对角线为0,右上和左下部分对称 
  • 第i个顶点的度等于第i行1的个数和,等于第i列1的个数和
 有向图的邻接矩阵

有向图的邻接矩阵特点:

  • 主对角线为0,不一定对称
  • 第i个顶点的出度等于第i行1的个数
  • 第i个顶点的入度等于第i列1的个数
  • 顶点的度=第i行元素之和+第i列元素之和
网(赋权图)的邻接矩阵

网是带有路径长度的图,所以对比上面的矩阵,我们只需要把通路1,换成路径的长度即可。

 代码表示
#define Maxnum 100//最大顶点数
//数据类型
typedef struct d { 
	char id[10];
	//……
}
ElemType;
//图的邻接数组
typedef struct graph {
	ElemType vexs[Maxnum];//图数据
	int arcs[Maxnum][Maxnum];//二维数组
	int vexnum;//点数
	int arcnum;//边数
}Graph;

2.邻接表

邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对于图的每个顶点建立一个容器( n个顶点建立 n 个容器),第 i 个容器中的结点包含顶点vi 的所有邻接顶点。

一个邻接表需要两种存储结构:顶点表结点边表结点 

  • 顶点:
    •  按编号顺序将顶点数据存储在一维数组中
  • 关联同一顶点的边 (以顶点为尾的弧)
    • 用线性链表存储

无向图的邻接表

特点:

  • 邻接表不唯一
  • 若无向图中有 n个顶点e条边,则其邻接表需 n个头结点和2e 个表结点。适宜存储稀疏图。

有向图的邻接表

特点:

  • 找出度易找入度难
  • 顶点 vi的出度为第i个单链表中的结点个数。
  • >顶点 vi的入度为整个单链表中邻接点域值是 i-1的结点个数。

代码表示
//数据结构体
typedef struct d {
	char id[10];//字符串编号
	//………………
}ElemType;
//边节点存储结构
typedef struct arcnode {
	int index;//指向顶点的位置
	int weight;//权
	struct arcnode* nextarc;//指向下一个边节点
}Anode;
//顶点结点存储结构
typedef struct vexnode {
	ElemType data;
	Anode* firstarc;
}Vhead;
//图结构
typedef struct {
	Vhead* vertices;
	int vexnum;
	int arcnum;
}Graph;

3.邻接矩阵和邻接表对比

邻接矩阵

 优点

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

缺点

  • 不便于增加和删除顶点
  • 浪费空间——存稀疏图 (点很多而边很少)有大量无效元素,但是对密图 (特别是完全图) 还是很合算的
  • 浪费时间——统计稀疏图中一共有多少条边
邻接表

优点

  • 对于稀疏图来说,邻接表比邻接矩阵更加省空间。
  • 方便遍历某个顶点的所有邻接点,时间复杂度为 O (degree)。
  • 邻接表算法实现简单,易于修改和扩展。

 缺点

  • 重边不好处理 判重比较麻烦 ,还要遍历已有的边,不能直接判断
  • 对确定边的操作效率不高
  • 不方便计算顶点的入度

图的创建

1.邻接矩阵创建图(网)

下面代码是无向网的创建 

#include<stdio.h>
#include<stdlib.h>

#define Maxint 32767
#define Maxnum 100//最大顶点数
//数据类型
typedef struct d { 
	char id[10];
	//……
}
ElemType;
//图的邻接数组
typedef struct graph {
	ElemType vexs[Maxnum];//图数据
	int arcs[Maxnum][Maxnum];//二维数组
	int vexnum;//点数
	int arcnum;//边数
}Graph;

//节点id查找下标
int Locate_vex(Graph G, char* id) {
	for (int i = 0; i < G.vexnum; i++)
		if (strcmp(G.vexs[i].id,id)==0)
			return i;
	return -1;
}

//构造邻接矩阵(无向图,对称矩阵)(有向图)赋权图
void Create_graph(Graph* G) {
	printf("请输入顶点个数和边的个数:\n");
	scanf("%d %d", &G->vexnum, &G->arcnum);//输入点数边数
	printf("请输入顶点数据:\n");
	for (int i = 0; i < G->vexnum; i++) {
		scanf("%s", G->vexs[i].id);
	}
	for (int x = 0; x < G->vexnum; x++) {
		for (int y = 0; y < G->vexnum; y++) {
			if (x == y)
				G->arcs[x][y] = 0;//对角线初始化为0
			else
				G->arcs[x][y] = Maxint;//其他初始化为Maxint
		}
	}
	printf("请输入边相关数据:\n");
	for (int k = 0; k < G->arcnum; k++) {
		char a[10], b[10];
		int w;
		scanf("%s %s %d", a, b, &w);
		//a->b
		int i = Locate_vex(*G, a);
		int j = Locate_vex(*G, b);
		//矩阵赋值
		G->arcs[i][j] = w;
		G->arcs[j][i] = w;//删掉这个,表示有向图
	}
}

//输出矩阵
void print_matrix(Graph G) {
	printf("矩阵为:\n");
	for (int i = 0; i < G.arcnum; i++) {
		for (int j = 0; j < G.arcnum; j++)
			printf("%-5d ", G.arcs[i][j]);
		printf("\n");
	}
	printf("图的顶点个数和边数:%d,%d\n", G.vexnum, G.arcnum);
}

结果如下: 

输入图的结构如下所示: 

 2.邻接表创建图(网)

对于邻接表的创建,我们是先去创建好顶点表数组,然后通过遍历和头插法把数据作为边表节点插入到顶点表的后面,最后形成邻接表链。代码如下:

#include<stdio.h>
#include<string.h>
//数据结构体
typedef struct datatype {
	char id[10];//字符串编号
	//………………
}ElemType;
//边节点存储结构
typedef struct arcnode {
	int index;//指向顶点的位置
	int weight;//权
	struct arcnode* nextarc;//指向下一个边节点
}Anode;
//顶点结点存储结构
typedef struct vexnode {
	ElemType data;
	Anode* firstarc;
}Vhead;
//图结构
typedef struct {
	Vhead* vertices;
	int vexnum;
	int arcnum;
}Graph;

//顶点查找下标
int Locate_vex(Graph G, ElemType v) {
	for (int i = 0; i < G.vexnum; i++)
		if (strcmp(G.vertices[i].data.id,v.id)==0)
			return i;
	return -1;
}

//创建头节点
void Create_vexhead(Graph *G,int n) {
	G->vertices = (Vhead*)malloc(sizeof(Vhead) *n);
	if (!G->vertices) {
		printf("ERROR\n");
		exit(-1);
	}
	else {
		for (int i = 0; i < n ; i++) {
			scanf("%s", G->vertices[i].data.id);
			G->vertices[i].firstarc = NULL;
		}
	}
}
//创建一个边节点
Anode* Create_arcnode(int loca, int w) {
	Anode* arc = (Anode*)malloc(sizeof(Anode));
	if (!arc)
	{
		printf("ERROR\n");
		exit(-1);
	}
	arc->index = loca;
	arc->nextarc = NULL;
	arc->weight = w;
	return arc;
}
//创建邻接表(无向图)(有向图)
void Create_graph(Graph* G) {
	printf("输入顶点数和边数:\n");
	scanf("%d %d", &G->vexnum, &G->arcnum);

	printf("输入顶点数据:\n");
	Create_vexhead(G, G->vexnum);

	printf("输入边数据:\n");
	for (int k = 0; k <G->arcnum; k++) {
		ElemType a, b;
		int w;
		scanf("%s%s%d", a.id, b.id, &w);
		int i = Locate_vex(*G, a);
		int j = Locate_vex(*G, b);
		//头插法
		//a->b
		Anode* p = Create_arcnode(j, w);
		p->nextarc = G->vertices[i].firstarc;
		G->vertices[i].firstarc = p;
		//如果创建有向图的话,直接把下面的代码删掉即可
		//b->a
		Anode* q = Create_arcnode(i, w);
		q->nextarc = G->vertices[j].firstarc;
		G->vertices[j].firstarc = q;
	}
}

//访问
void visit(Graph G, int index) {
	printf("%s ", G.vertices[index].data.id);
}

//输出图
void print(Graph G) {
    printf("以下是图的顶点连接关系:\n");
	for (int i = 0; i < G.vexnum; i++) {
		printf("%s:", G.vertices[i].data.id);
		Anode* cur= G.vertices[i].firstarc;
		while (cur) {
			visit(G, cur->index);
			cur = cur->nextarc;
		}
		printf("\n");
	}
	printf("顶点和边数分别是:%d %d\n", G.vexnum, G.arcnum);
}

测试结果:

好了,以上就是今天的全部内容了,我们下一期学习图的遍历,下次见咯! 

分享一张壁纸:

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

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

相关文章

idea2023配置maven

看过【黑马程序员Maven全套教程&#xff0c;maven项目管理从基础到高级&#xff0c;Java项目开发必会管理工具maven】https://www.bilibili.com/video/BV1Ah411S7ZE?p9&vd_sourceedf9d91e5a0a27db51e3d6d4b9400637 配置的&#xff0c;前提要素配置也在这个课程里有啦&…

在 Tubi 做 Tech Lead 有多刺激!

上周我们发布了一篇《当你在 Tubi 是一位 Tech Lead》采访稿&#xff0c;后台收到了这样一条留言&#xff0c;说出了许多技术人在选择管理岗位还是继续深耕技术方向时的纠结&#xff1a; ‘有些同事更喜欢投入精力处理有挑战的事情&#xff0c;而不愿花费太多时间进行人际沟通&…

Janus: 逆向思维,以数据为中心的MoE训练范式

文章链接&#xff1a;Janus: A Unified Distributed Training Framework for Sparse Mixture-of-Experts Models 发表会议: ACM SIGCOMM 2023 (计算机网络顶会) 目录 1.背景介绍all-to-allData-centric Paradigm 2.内容摘要关键技术Janus细粒度任务调度拓扑感知优先级策略预取…

30二叉树-了解二叉树

目录 树的定义 二叉树&#xff08;Binary Tree&#xff09; 二叉树的存储方式 链式存储 顺序存储 二叉树的遍历方式 LeetCode之路——144. 二叉树的前序遍历 分析 树的定义 树结构&#xff08;Tree Structure&#xff09;是一种分层的非线性数据结构&#xff0c;它由节…

【OpenCV实现鼠标绘图,轨迹栏做调色板,图像的基本操作】

文章目录 鼠标绘图轨迹栏做调色板图像的基本操作 鼠标绘图 在OpenCV中操作鼠标事件 函数&#xff1a;cv.setMouseCallback() 目的是在鼠标双击的地方画一个圆。首先&#xff0c;我们需要创建一个鼠标回调函数&#xff0c;该函数会在鼠标事件发生时执行。鼠标事件包括左键按下…

PyQt学习笔记-获取Hash值的小工具

目录 一、概述1.1 版本信息&#xff1a;1.2 基本信息&#xff1a;1.2.1 软件支持的内容&#xff1a;1.2.2 支持的编码格式 1.3 软件界面图 二、代码实现2.1 View2.2 Controller2.3 Model 三、测试示例 一、概述 本工具居于hashlibPyQtQFileDialog写的小工具&#xff0c;主要是…

中国移动启动算网大脑“天穹”全网试商用

10月12日&#xff0c;中国移动在2023全球合作伙伴大会主论坛正式启动算网大脑“天穹”全网试商用&#xff0c;全面开启算力网络2.0新征程&#xff0c;标志着中国移动算力网络迈向“融合统一”新阶段。 为落实国家“东数西算”战略&#xff0c;中国移动开创性提出算力网络新理念…

操作系统【OS】微内核

基本概念 微内核结构将操作系统划分为两大部分&#xff1a;微内核多个服务器微内核包含&#xff1a; 与硬件处理紧密相关的部分一些较基本的功能客户和服务器间的通信客户与服务器之间是借助微内核提供的消息传递机制来实现交互的 基本功能 进程管理 进程的通信、切换、调度…

【算法练习Day24】递增子序列全排列全排列 II

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 递增子序列容易出错的地方 …

微信手续费2023标准

不管是微信还是支付宝&#xff0c;商户最低的收款手续费率可以达到0.2%费率。一般我们普通商户的收款费率一般在0.6左右&#xff0c;当然也有使用0.3的&#xff0c;也就是1万元的费率是30-60块钱&#xff0c;对于一些流水比较大的商家来说&#xff0c;确实很有必要把这个手续费…

【实用技巧】Latex写算法伪代码(格式篇)

本文主要介绍个人在编写Latex算法伪代码时所遇到的格式问题。 目录 包冲突换行与缩进算法换页 包冲突 \usepackage{algorithm} \usepackage{algorithmic} \usepackage{algorithmicx} \usepackage{algpseudocode} 网上查找算法伪代码第三方包&#xff0c;主要会跳出来这四…

虹科案例 | 瑞士Agroscope研究所利用压力传感器自动测量反刍动物(奶牛)的咀嚼运动

——用于动物测量研究的数据记录仪&#xff1a;虹科MSR145 瑞士Agroscope研究所隶属于联邦农业办公室&#xff0c;是农业、食品和环境领域可持续发展的推动力量&#xff0c;为农业和环境政策决策以及法规执行提供科学和技术基础。 作为Agroscope研究所的合作代表&…

【超详细】CentOS 7安装MySQL 5.7【安装及密码配置、字符集配置、远程连接配置】

准备工作&#xff1a;CentOS 7系统&#xff0c;并确保可以联通网络 1、获取MySQL 5.7 Community Repository软件包 注意&#xff1a;这里使用的是root用户身份。 wget https://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm2、安装软件包 rpm -ivh mysql5…

PyTorch入门教学——TensorBoard使用

1、TensorBoard简介 TensorBoard是Google开发的一个机器学习可视化工具。其主要用于记录机器学习过程&#xff0c;例如&#xff1a; 记录损失变化、准确率变化等记录图片变化、语音变化、文本变化等。例如在做GAN时&#xff0c;可以过一段时间记录一张生成的图片绘制模型 2、…

数字秒表VHDL启动暂停清零,源码和视频

名称&#xff1a;数字秒表VHDL启动暂停清零&#xff08;代码在文末付费下载&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; 数字秒表 使用VHDL语言设置数字秒表。要求具有百分秒、秒和分钟显示,百分秒范围00-99,秒范围00-59,分钟范围0…

《java 桌面软件开发》swing 以鼠标为中心放大缩小移动图片

swing 使用Graphic2D 绘制图片&#xff0c;要实现对图片进行缩放和自由拖动。 1.以鼠标所在的位置为中心&#xff0c;滚轮控制缩放 2.缩放后再支持鼠标拖动。 基本原理&#xff1a; 利用scale() 函数。进行缩放。但是要注意的地方是&#xff0c;如果是在 public void paintCom…

Linux 下安装配置部署MySql8.0

一 . 准备工作 MySQL安装包&#xff1a;在官网下载需要的版本&#xff0c;这里我用的版本是 MySQL 8.0.34 https://dev.mysql.com/downloads/mysql/ 本次linux机器使用的是阿里云ECS实例 二 . 开始部署 1. 将安装包上传至服务器 解压到当前文件夹 tar -zxvf mysql-8.0.34…

Python 实现http server接收mutipart/form-data文件 方法1

Python 实现http server接收mutipart/form-data文件 方法1 1 Server端代码2 客户端截图3 代码说明 1 Server端代码 import os from flask import Flask, request from werkzeug.utils import secure_filenameapp Flask(__name__) app.config[UPLOAD_FOLDER] E://recv//app.ro…

玩游戏缺失“d3d11.dll丢失“的问题的五种解决方案

在我日常的计算机维护工作中&#xff0c;经常遇到一些用户报告他们遇到了"d3d11.dll丢失"的问题。这是一个常见的Windows系统错误&#xff0c;通常会导致程序无法正常运行。在这篇文章中&#xff0c;我将分享我找到的五种有效的解决方法&#xff0c;以帮助这些用户解…

开源的容器运行时项目 Podman

本心、输入输出、结果 文章目录 开源的容器运行时项目 Podman前言Podman 简介Podman 与 Docker 的区别Podman 在使用上和 Docker 有什么区别从构建者角度分析 Podman 在使用上和 Docker 有什么区别从使用者角度分析 Podman 在使用上和 Docker 有什么区别 Podman 常用命令容器镜…