技术心得记录:图的概念和存储(邻接矩阵,邻接表)

简介: 技术心得记录:图的概念和存储(邻接矩阵,邻接表)

图的概念


为什么要有图


在学习图之前我们应该学习了,线性表和树;但是我们有没有考虑过为什么要有图,线性表和图的局限性优势上面呢?


线性表他仅仅局限于一个直接前驱和一个直接后继的关系。


树呢?树也仅仅只能有一个直接前驱也就是父节点。


那么这种多对多的关系怎么处理么? 这里我们就用到了图


图的概念


上面图片就是一个图


在线性表中我们把数据元素叫做元素,在树种叫做结点,在图中我们把他叫做顶点(Vertex);


两个顶点之间的连线叫做边;


有方向的叫做有向边,没方向的叫做无向边;


边上的数字代表边的权值,当图上有权值时他也叫做网


这些基本概念足以看懂一个图了那么上面怎么储蓄一个图呢?


图的储存-邻接矩阵


邻接矩阵的概念


邻接矩阵,它是什么形式呢?


形式就是我上面给书的图旁边的那个图;


首先 把图中的各个顶点排成一个行列式


有边的写1(或者边上的权值)没有的写无穷大(现在的图中我们不考虑顶点和顶点自己边)。


为什么要无穷大而不取0 呢因为有的边上的权值可能是0


邻接矩阵的定义


---------------------


/


这里首先定义一个vexs数组来存放各个顶点,然后建立arc以顶点数为行和列的行列式


vexs数组也就是没有显示出来实际行列式的第0行和第0列


/


typedef struct{


char vexs【MAXSIZE】;//顶点表


int arc【MAXSIZE】【MAXSIZE】;//领接矩阵可以看成边表


int N_v,N_e ; //定义顶点数字和边数


}M_g;


邻接矩阵创建


/


这个函数大概意思


就是首先接收到顶点数个边数,用顶点数为矩阵的长宽来初始化矩阵


然后接收某两个顶点之间的关系,改变矩阵中的默认值


/


void onCreateM_g(M_g x)


{


int i,j,k,w;


printf("请输入顶点数和边数\n");


scanf("%d%d",&x->N_v,&x->N_e);


printf("请依次各输入顶点\n");


for(i=0;i N_v;i++)


{


scanf("%d",&x->vexs【i】);


// puts("sdsdsds");


}


//


for(i = 0;i N_v;i++){


for(j = 0;j N_v;j++)


{


x->arc【i】【j】 = FALL;


}


}


for( k = 0; k N_e;k++)


{


printf("请输入(vi,vj)的上标i,下标j 和权 w \n");


scanf("%d%d%d",&i,&j,&w);


x->arc【i】【j】 = w;


x->arc【j】【i】 = x->arc【i】【j】;


}


}


实现领接矩阵


#include


#include


#define MAXSIZE 100


#define FALL 99999


//用99999来代表无穷大


/


这里首先定义一个vexs数组来存放各个顶点,然后建立arc以顶点数为行和列的行列式


vexs数组也就是没有显示出来实际行列式的第0行和第0列


/


typedef struct{


char vexs【MAXSIZE】;//顶点表


int arc【MAXSIZE】【MAXSIZE】;//领接矩阵可以看成边表


int N_v,N_e ; //定义顶点数字和边数


}M_g;


//实现


void onCreateM_g(M_g x)


{


int i,j,k,w;


printf("请输入顶点数和边数\n");


scanf("%d%d",&x->N_v,&x->N_e);


printf("请依次各输入顶点\n");


for(i=0;i N_v;i++)


{


scanf("%d",&x->vexs【i】);


// puts("sdsdsds");


}


//


for(i = 0;i N_v;i++){


for(j = 0;j N_v;j++)


{


x->arc【i】【j】 = FALL;


}


}


for( k = 0; k N_e;k++)


{


printf("请输入(vi,vj)的上标i,下标j 和权 w \n");


scanf("%d%d%d",&i,&j,&w);


x->arc【i】【j】 = w;


x->arc【j】【i】 = x->arc【i】【j】;


}


}


void ergodic (M_g x)


{ int i,j;


for(i=0;iN_v;i++)


{


for(j=0;jN_v;j++)


{


printf("%d\t",x->arc【i】【j】);


}


putchar('\n');


}


}


int main(){


M_g p;


p = (M_g)malloc(sizeof(M_g));


onCreateM_g(p);


ergodic (p);


return 0;


}


/


4 4


0 1 2 3


0 1 56


0 2 34


0 3 78


2 3 25


/


//复制上面的输入进去查看输出


图的储存-邻接表


邻接表的基本概念


1.为什么要有邻接表


可以想象如果有一个图他的顶点特别多而边只有一个?那么是不是用邻接矩阵特别浪费内存呢?


所以需要邻接表(不同于邻接表主要以链表形式实现)


2.怎么理解邻接表呢?


首先看上面b图,最边上的表我们给他起名——顶点表;其他的我们给另外的变我们给他起名边表;


3.顶点表


顶点表用来开始储存图中的各个顶点,可以看到我们给顶点表开辟了两个域,第一个域存放了顶点了第二个域呢?


我们可以看出来顶点表的第二个域指向了边表,所以在顶点表的第二个域里面我们存放边表类型让他变成边表的头结点指向边表;


4.边表


上图中边表有两个域一个存放和顶点边中有关系的顶点,另外一个也就是他的NEXT域和链表一样在后面没有时他指向为空,其实还可以给他加第三个域比如权值等等这个很简单了


这样各个就形成了一个邻接表了


邻接表的实现


首先是定义这个结构体类型


/


下面代码的总体意思就是先定义边表我们给了他3个域分别是顶点域 权值域和next域


在定义顶点表 他有两个域分别是顶点域和代表边表头结点的first_v域


最后我们定义一个顶点表的顺序表类型。类似于图b中最左边的那个顺序表


这样一个邻接表就定义好了


/


typedef int VertexType;/顶点类型有用户定义/


typedef struct EdgeNode//定义边表


{


int adjvex;//邻接点域 里面放各个和顶点表对应节点有关的顶点


int weight;//权值


struct EdgeNode next;


}EdgeNode;


typedef struct VertexNode /定义顶点表/


{


VertexType data;//顶点域,存储顶点信息


EdgeNode first_v;//边表的头指针


}VertexNode;


typedef struct //邻接表


{


VertexNode adjlist【M】; //用于存放头结点和顶点的顺序表;


int n_v,n_e;


}LinkdeGraph;


创建邻接表


下面代码的主要含义是


1.先获取到图中的顶点数和边数,然后以顶点数为最大创建顶点表数组并且初始化


2.然后定义一个边表类型,输入某个边上的两个顶点,并且用头插发插入


边的表示(vi vj)表示连接vi vj的边


3.函数解释


大概意思就是接收到边上的两个顶点后,把和i有边的j节点用头插发插在顶点表中有i顶点那一段之后;


void onCreate_L(LinkdeGraph p,int c)//等于0表示建立为无向图


{


int i,j,k;


EdgeNode e;


printf("请输入顶点数和边数:\n");


scanf("%d%d",&p->n_v,&p->n_e);


printf("请依次输入顶点\n");


for(i = 0; i n_v; i++ )//输入顶点信息,建立顶点表


{


scanf("%d",&p->adjlist【i】.data);//输入顶点信息


p->adjlist【i】.first_v = NULL; //初始状态默认边表为空


}


for(k = 0 ; k n_e;k++)//建立边表


{


printf("请输入边(vi,vj)上的顶点序号:\n");


scanf("%d%d",&i,&j);//输入边vivj上的顶点序号


e = (EdgeNode)malloc(sizeof(EdgeNode));//开辟边表的空间


/


头插法


/


e->adjvex = j; //顶点为j


e->next = p->adjlist【i】.first_v;//将边表e作为头指针放进顶点表的first域


p->adjlist【i】.first_v = e;


if(c == 0)


{


e = (EdgeNode)malloc(sizeof(EdgeNode));


e ->adjvex = i;


e->next = p->adjlist【j】.first_v;


p->adjlist【j】.first_v = e;


}


}


}


实现领接表


#include


#include


#define M 20


typedef int VertexType;/顶点类型有用户定义/


typedef struct EdgeNode//定义边表


{


int adjvex;//邻接点域 里面放各个和顶点表对应节点有关的顶点


int weight;//权值


struct EdgeNode next;


}EdgeNode;


typedef struct VertexNode /定义顶点表/


{


VertexType data;//顶点域,存储顶点信息


EdgeNode first_v;//边表的头指针


}VertexNode;


typedef struct //邻接表


{


VertexNode adjlist【M】; //用于存放头结点和顶点的顺序表;


int n_v,n_e;


}LinkdeGraph;


//创建邻接表


void onCreate_L(LinkdeGraph p,int c)//等于0表示建立为无向图


{


int i,j,k;


EdgeNode e;


printf("请输入顶点数和边数:\n");


scanf("%d%d",&p->n_v,&p->n_e);


printf("请依次输入顶点\n");


for(i = 0; i n_v; i++ )//输入顶点信息,建立顶点表


{


scanf("%d",&p->adjlist【i】.data);//输入顶点信息


p->adjlist【i】.first_v = NULL; //初始状态默认边表为空


}


for(k = 0 ; k n_e;k++)//建立边表


{


printf("请输入边(vi,vj)上的顶点序号:\n");


scanf("%d%d",&i,&j);//输入边vivj上的顶点序号


//代码效果参考:http://www.jhylw.com.cn/523032533.html

e = (EdgeNode)malloc(sizeof(EdgeNode));//开辟边表的空间

/


头插法


/


e->adjvex = j; //顶点为j


e->next = p->adjlist【i】.first_v;//将边表e作为头指针放进顶点表的first域


p->adjlist【i】.first_v = e;


if(c == 0)


{


e = (EdgeNode)malloc(sizeof(EdgeNode));


e ->adjvex = i;


e->next = p->adjlist【j】.first_v;


p->adjlist【j】.first_v = e;


}


}


}


int main(){


int c = 0;


LinkdeGraph p;


p = (LinkdeGraph*)malloc(sizeof(LinkdeGraph));


onCreate_L(p,c);


return 0;


}

相关文章
|
10月前
|
机器学习/深度学习 缓存 PyTorch
为什么要用TorchEasyRec processor?
TorchEasyRec处理器支持Intel和AMD的CPU服务器及GPU推理,兼容普通PyTorch模型。它具备TorchEasyRec的特征工程(FG)和模型推理功能,提供更快的推理性能,降低成本。通过Item Feature Cache特性,它能够缓存特征以减少网络传输,进一步提升特征工程与推理的速度。
247 2
|
人工智能 Java Serverless
【MCP教程系列】搭建基于 Spring AI 的 SSE 模式 MCP 服务并自定义部署至阿里云百炼
本文详细介绍了如何基于Spring AI搭建支持SSE模式的MCP服务,并成功集成至阿里云百炼大模型平台。通过四个步骤实现从零到Agent的构建,包括项目创建、工具开发、服务测试与部署。文章还提供了具体代码示例和操作截图,帮助读者快速上手。最终,将自定义SSE MCP服务集成到百炼平台,完成智能体应用的创建与测试。适合希望了解SSE实时交互及大模型集成的开发者参考。
12470 60
|
11月前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(05)突击MVCC核心原理 | 左右护法ReadView视图和undoLog版本链强强联合
2024年小结:感谢阿里云开发者社区每月的分享交流活动,支持持续学习和进步。过去五个月投稿29篇,其中17篇获高分认可。本文详细介绍了MySQL InnoDB存储引擎的MVCC机制,包括数据版本链、readView视图及解决脏读、不可重复读、幻读问题的demo演示。
|
Web App开发 Windows
Windows 记录一次磁盘相关的PC卡顿问题
【10月更文挑战第26天】本文记录了一次Windows系统中因磁盘问题导致的PC卡顿现象及其解决过程。通过查看任务管理器发现磁盘使用率高,经磁盘碎片整理、优化启动项与后台程序、更新磁盘驱动等步骤,最终解决了卡顿问题。建议定期进行磁盘维护,合理管理启动项,及时更新驱动以预防类似问题。
286 5
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
关系型数据库 MySQL 数据库
什么是数据库触发器?
【8月更文挑战第3天】
1707 10
什么是数据库触发器?
|
存储 关系型数据库 MySQL
MySQL 字符字段长度设置详解:语法、注意事项和示例
MySQL 字符字段长度设置详解:语法、注意事项和示例
1102 0
|
关系型数据库 MySQL 数据库
debian11编译安装freeswitch
debian11编译安装freeswitch
420 0
|
存储 机器学习/深度学习 人工智能
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
数据结构学习笔记——图的存储结构(邻接矩阵和邻接表)
|
监控 NoSQL 算法
【MongoDB】 MongoDB的副本集是什么?
【4月更文挑战第1天】【MongoDB】 MongoDB的副本集是什么?