图的基础知识1

我们先来了解一下啥是图,图是一个什么样的东西:
:图(Graaph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。
无向图:若顶点vi到vj之间的边没有方向,则称这条边为无向边(Edge),用无序偶对(vi,vj)来表示。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图(Undirected graphs)。如下图所示则为一个无向图:
在这里插入图片描述
有向图:若顶点vi到vj之间的边有方向,则称这条边为有向边,也称为弧(Arc),用有序偶<vi,vj>来表示。vi称为弧尾,vj称为弧头。如果图中任意两个顶点之间的边都是有向边,则称该图为有向图(Directed graphs)。如下图所示则为一个有向图:
在这里插入图片描述
简单图:在图中,若不存在顶点到其自身的边,且同一条边不重复出现,则称这样的图为简单图。
:有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数叫做权(Weight)。
:带权的图通常称为网(Network)。
第一个顶点到最后一个顶点相同的路径称为简单路径。除了第一个顶点和最后一个定点之外,其余顶点不重复出现的回路,成为简单回路或简单环。
在无向图G中,如果从顶点v到顶点 v’有路径,则称v和 v’是连通的。如果对于图中任意两个顶点vi,vj∈E,vi和vj都是连通的,则称G是连通图(Connected Graph)。
理解了图的概念,我们下来了解一下图是怎样存到计算机里面的,用计算机的语言表示它?
图不想树,有惟一的前驱,它可能与很多个前驱和后继。
在这里我说一种存储方法:邻接矩阵
图的邻接矩阵(Adjacency Maatrix)存储方式是用两个数组来表示图。一个一维数组存储图顶点信息 ,一个二维数组(成为邻接矩阵)存储图中的边或弧的信息。
我们来看一个实例,看一下怎样用图或者语言表示:
先来看一下要表示的图:
在这里插入图片描述
我们这里先用一个数组表示一下它的顶点信息,称为顶点数组:

v0v1v2v3

在表示一下边的二位数组,称为边数组:

v0v1v2v3
v00111
v11010
v21101
v31010

着里连通表示1,不连通表示0,若此图为有向图,从弧尾到弧头表示为1,弧头到弧尾表示为0,若为带权值的图,则用权值来表示1,对于以后的计算会更加方便。设置这样两个数组,我们就可以有效的对一个图进形表示了。
下来我们对图需要的数组进行创建,此处为结构体的代码:

typedef char VertexType;/*顶点char型*/
typedef int EdgeType;/*边上的权值*/
#define MAXVEX 100/*最大顶点数*/
#define INFINITY -1/*用-1来表示无穷大,即不连通*/
typedef struct
{
 VertexType vexs[MAXVEX];/*顶点表*/
 EdgeType arc[MAXVEX][MAXVEX];/*邻接矩阵,可看作边表*/
 VCoordinate pos[MAXVEX];
 int numVertexes, numEdges;/*图中当前的顶点数和边数*/
}MGraph;

下面我们来用代码表示一个图怎样输入:

void CreateMGraph(MGraph *G)/*输入图*/
{
 FILE* fp;
 fp = fopen("\Graph.txt", "r");
 int i, j, k, w;
 printf("输入顶点数和边数:\n");
 fscanf(fp,"%d,%d\n",&G->numVertexes,&G->numEdges);
 /*fflush(stdin);*/
 for (i = 0; i < G->numVertexes; i++)
 {
  fscanf(fp,"%c\n",&G->vexs[i]);
 }
 G->vexs[G->numVertexes] = '\0';
 for (i = 0; i < G->numVertexes; i++)
 {
  for (j = 0; j < G->numVertexes; j++)
  {
   G->arc[i][j] = INFINITY;
  }
 }
 for (k = 0; k < G->numEdges; k++)
 {
  printf("输入边(vi,vj)上的下标i,下标j和权w:\n");
  /*fflush(stdin);*/
  fscanf(fp,"%d,%d,%d\n", &i, &j, &w);
  G->arc[i-1][j-1] = w;
  G->arc[j-1][i-1] = G->arc[i-1][j-1];
 }

邻接矩阵是一种很好的用来表示图在计算机上存储的方式,比较容易理解,但是我们发现,对于边数相对顶点较少的图,这种结构的存储方式对,空间的浪费比较大,所以下面我们介绍一种新的存储方式:邻接表
邻接表:我们把数组与链表相结合的存储方式称为邻接表(Adjacency List)。
邻接表的存储方式是这样的:

  1. 图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外 ,对于顶点数组,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
  2. 图中每个顶点Vi的所有领接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点V~i ~的边表,有向图则称为顶点 Vi作为弧尾的出边表。

例如下图所示的就是一个无向图和他的邻接表结构:
在这里插入图片描述
在这里插入图片描述
由图可知,顶点表的各个节点由data和firstedge两个域表示,data是数据域,存储顶点的信息,firstedge是指针域,指向边表的第一个 结点,即此顶点的第一个邻接顶点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,next则存储指向边表中下一个结点的指针。
下面我们定义一下邻接表的结构体:

typedef char VertexType;/*定义顶点类型*/
typedef int EdgeType;/*如果是有向边,定义权值类型*/
typedef struct EdgeNode/*边表结点*/
{
int adjvex;/*邻接点域,存储该顶点对应的下标*/
EdgeType weight;/*用于存储权值,对于非网图可以不需要*/
struct EdgeNode* next;/*链域,指向下一个邻接点*/
}EdgeNode;
typedef struct VertexNode/*顶点表结点*/
{
 VertexType data;/*顶点域,存储顶点信息*/
 EdgeNode* firstedge;/*边表头指针*/
 }VertexNode,AdjList[MAXVEX];
 typedef struct
 {
 AdjList adjList;
 int numVertexes,numEdges;/*图中当前顶点数和边数*/
 }GraphAdjList;

无向图的邻接表的创建,代码如下:

void CreatALGraph(CreatALGraph* G)
{
int i,j,k;
EdgeNode* e;
printf("输入顶点数和边数:\n");
scanf("%d,%d",&G->numVertexes,&G->numEdges);/*输入顶点数和边数*/
for(i=0;i<G->numVertexes;i++)/*读取顶点信息,建立顶点表*/
{
scanf(&G->adjList[i].data);/*输入顶点信息*/
G->adjList[i].firstedge=NULL;/*将边表置为空表*/
}
for(k=0;k<G->numEdges;k++)/*建立边表*/
{
printf("输入边(vi,vj)上的顶点序号:\n");
scanf("%d,%d",&i,&j);/*输入边(vi,vj)上的顶点序号*/
e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向内存申请空间生成边表结点*/
e->adjvex=j;/*邻接序号为j*/
e->next=G->adjList[i].firstedge;/*将e指针指向当前顶点指向的结点*/
G->adjList[i].firstedge=e;/*将当前顶点 的指针指向e*/
e=(EdgeNode*)malloc(sizeof(EdgeNode));/*向内存申请空间生成边表结点*/
e->adjvex=i;/*邻接序号为i*/
e->next=G->adjList[j].firstedge;/*将e指针指向当前顶点指向的结点*/
G->adjList[j].firstedge=e;/*将当前顶点 的指针指向e*/
}
}

对于有向图,邻接表是有问题的,当他关心了出度问题,想了解入度就必须要遍历整个图才行,这样就大大增加了时间复杂度。
下面说两种储存方式:

  1. 十字链表(Orthogonal List)
    它顶点表的结构如下表所示:
datafirstinfirstout

其中firstin表示入边表头指针,指向该顶点的入边表中第一个结点,firstout表示出边表头指针,指向该顶点的出边表中的第一个节点。
定义他的边表结点结构如下表所示:

tailvexheadvexheadlinktaillink

其中tailvex是指弧起点在顶点表的下标,headvex是指弧终点在顶点表中的下标,headlink是指入边表指针域,指向终点相同的下一条边,taillink是指边表指针域,指向起点相同的下一条边。
下面我们用图来表示一下:
在这里插入图片描述
十字链表的好处就是因为把邻接表和逆邻接表整合在一起,这样即容易找到以vi为尾的弧,也容易找到以vi为头的弧,因而容易求得顶点的出度和入度。
2. 邻接多重表
上面我们说了对有向图的优化,下面说一下无向图的存储优化结构。
在上面说的存储结构中,我们如果关注的重点是顶点,那么邻接表很不错,但如果我么更注重边的操作,比如删除某一条边,或增添等操作,就意味着,需要找到这两条边的两个边结点进行操作,还是比较麻烦的。
因此我们对狮子链表进行了一些改进,成为了我们现在的邻接多重表,其边表结点结构如下表所示:

ivexinlinkjvexjlink

其中ivex和jvex是与某条边依附的两个顶点表中下标。inlink指向依附顶点ivex的下一条边,jlink指向依附顶点jvex的下一条边。这就是邻接多重表结构。
下面用图表示一下:
在这里插入图片描述
今天先写这么多,图的剩余知识,下次在写。
可能有一些地方还不完美,我后续还会继续改进,也希望大家指出不当之处,以便改进,共同进步,谢谢赏阅!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值