[C语言]图的总结

本文详细介绍了图的定义、类型、存储结构和遍历算法,包括无向图、有向图、连通图的概念,以及最小生成树、最短路径、拓扑排序和关键路径等核心概念。同时,提到了邻接矩阵、邻接表等图的存储方法,并探讨了Dijkstra、Floyd-Warshall等求解最短路径的算法。
摘要由CSDN通过智能技术生成

在这里插入图片描述

定义: 由顶点的有穷非空集合和顶点之间的边的集合组成,表示为:G(V,E),其中,G表示一个图,V表示顶点集合,E表示边的集合

注:顶点集合不能为空,边集为空

各种图定义

  1. 无向边:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边(Edge),可用无序偶对表示为:(Vi,Vj)

    若图中任意两个顶点之间的边都是无向边,则称该图为无向图.
    在这里插入图片描述

    G = (V,{E})

    V = {A,B,C,D}

    E = {(A,B),(A,C),(B,C),(C,D),(D,A)}

  2. 有向边:若顶点Vi到Vj的边有方向,则称此条边为有向边,也成为弧(Arc),可用有序偶对表示为:<Vi,Vj>,

    Vi为弧尾(Tail),Vj为弧头(Head).

    若图中任意两个顶点之间的边都是有向边,则称此图为有向图.
    在这里插入图片描述
    G = (V,{E})

    V = {A,B,C,D}

    E = {<A,D>,<B,A>,<C,A>,<B,C>}

  3. 简单图:在图中不存在顶点到自身的边,且同一条边不重复出现,则称这样的图为简单图

  4. 无向完全图:在无向图中,任意两个顶点之间都有边,称此图为无向完全图.

    含有N个顶点的无向完全图拥有的边数为:
    N ∗ ( N − 1 ) / 2 N*(N-1)/2 N(N1)/2
    所以N个顶点的无向图最多拥有N*(N-1)/2条边
    在这里插入图片描述

  5. 有向完全图:在有向边中,任意两个顶点之间都存在方向互为相反的两条弧,则称此图为有向完全图,

    含有N个顶点的有向完全图拥有的边数为:
    N ∗ ( N − 1 ) N*(N-1) N(N1)
    所以N个顶点的有向图最多拥有N*(N-1)/2条边
    在这里插入图片描述

  6. 稠密图与稀疏图:对于N个顶点和M条边的图,M远小于N^2的图成为稀疏图,M较大的图称为稠密图(边或弧多称为稠密图,反之称为稀疏图).

  7. 权值:与图的边或弧相关的数叫做,带权的图称为.
    在这里插入图片描述

  8. 子图:存在两个图 G = (V,{E}) 和 G’ = (V’,{E’}) 若V’ 包含于 V,E’ 包含于 E.则称G’为G的子图(Subgraph)
    在这里插入图片描述

图的顶点与边间关系

  1. 对于无向图G = (V,{E}),若(V,V’) 属于 E则称V和V’互为邻接点(Adjacent),即V和V’相邻接

    V的度(Degree)是与V相连接的边的数目记为:TD(V).

    边数(e)是各顶点度数和的一半即
    e = 1 / 2 ∗ ∑ ( i = 1 , n ) T D ( V i ) e = 1/2*\sum (i = 1,n)TD(Vi) e=1/2(i=1,n)TD(Vi)

  2. 对于有向图G = (V,{E}),以顶点V为头的弧的数目称为V的入度(InDegree),记作ID(V)

    以顶点V为尾的弧的数目称为V的出度(OutDegree),记作OD(V).

    顶点D的度为TD(V) = ID(V) + OD(V)

    所以边数(e)为所有顶点的入度和或者出度和:
    e = 1 / 2 ∗ ∑ ( i = 1 , n ) I D ( V i ) = ∑ ( i = 1 , n ) O D ( V i ) e = 1/2* \sum(i = 1,n)ID(Vi) = \sum(i = 1,n)OD(Vi) e=1/2(i=1,n)ID(Vi)=(i=1,n)OD(Vi)

  3. 无向图G = (V,{E})中的路径(Path)是一个顶点序列(Vi,Vj),其中(Vi,Vj) 属于 E.

    路径的长度是路径上的边或弧的数目

  4. 第一个顶点到最后一个顶点相同的路径称为回路或者(Cycle).序列中顶点不重复出现的路径称为简单路径,除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路或者简单环.

连通图的相关术语

  1. 连通图:在无向图G中,如果从顶点v到顶点v’有路径,则称v和v’是连通的。如果对于图中任意两个顶点Vi, Vj∈E, Vi和Vj都是连通的,则称G是连通图(ConnectedGraph).
    在这里插入图片描述

    例子:
    在这里插入图片描述

    此图的连通分量为:
    在这里插入图片描述


    在这里插入图片描述

  2. 一个连通图的生成树是一个极小的连通子图,它含有全部N个顶点,拥有构成一颗树的N-1条边.

所以:一个图有N个顶点和小于N-1条边,一定不是连通图,多余N-1条边,则一定有环.

图的存储结构

  1. 邻接矩阵(AdjGraph):使用两个矩阵来表示图:一维数组Vex存储顶点,二维数组map存储边或弧的信息

    可以存储边数较多的稠密图

    /*构建邻接矩阵*/
    typedef char VexType;	//顶点的数据类型
    typedef int EdgeType;	//边上的权值类型
    #define MAXVEX 100  //最大顶点数
    #define INF	9999	//表示无穷大
    
    typedef struct
    {
         
    	VexType vexs[MAXVEX];	//顶点表
    	EdgeType map[MAXVEX][MAXVEX];	//邻接矩阵
    	int vexnum,edgenum;	//顶点数和边数
    } AdjGraph; //邻接矩阵
    
    void InitAdjGraph(AdjGraph* M)//初始化邻接矩阵
    {
         
    	printf("输入顶点数和边数:");
    	scanf("%d%d",&(M->vexnum),&(M->edgenum));
    	for(int i = 0; i<M->vexnum; i++)
    	{
         
    		for(int j = 0; j<M->vexnum; j++)
    		{
         
    			if(i == j)
    				M->map[i][j] = 0;//自身不能到自身
    			else
    				M->map[i][j] = INF;
    		}
    	}
    	fflush(stdin);
    	printf("输入顶点:");//构建顶点表
    	for(int i = 0; i<M->vexnum; i++)
    		scanf("%c",&(M->vexs[i]));
    	fflush(stdin);
    	for(int i = 0; i<M->edgenum; i++) //构建邻接矩阵
    	{
         
    		printf("输入边(Vi,Vj)的下标i,j和该边权值w:");
    		int l,r;
    		EdgeType w;
    		scanf("%d%d%d",&l,&r,&w);
    		M->map[l][r] = w;
    //		M->map[r][l] = w;//有向图 
    	}
    }
    
    void Print(AdjGraph* M)//展示
    {
         
    	printf("顶点表为\n");
    	for(int i = 0; i<M->vexnum; i++)
    		printf("%c ",M->vexs[i]);
    	printf("\n邻接矩阵为\n");
    	for(int i = 0; i<M->vexnum; i++)
    	{
         
    		for(int j = 0; j<M->vexnum; j++)
    			printf("%-4d ",M->map[i][j]);
    		putchar('\n');
    	}
    }
    
    int main()
    {
         
        AdjGraph *M = (AdjGraph*)malloc(sizeof(AdjGraph));
    	InitAdjGraph(M);
    	Print(M);
        return 0;
    }
    

    ​ 效果图:
    在这里插入图片描述

  2. 邻接表(AdjList):采用数组和链表相结合的方式

    可以存储边较少的图
    在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef char VexType;	//顶点的数据类型
typedef int EdgeType;	//边上的权值类型
#define MAXVEX 100  //最大顶点数
#define INF 9999//表示不连通

typedef struct EdgeNode
{
   
	int index;	//节点下标
	EdgeType weight;	//权值
	struct EdgeNode* next;
} EdgeNode;	//边表节点

typedef struct
{
   
	VexType vex;	//顶点
	EdgeNode *firstedge;	//指向第一个边节点
} VexNode; //顶点表节点

typedef struct
{
   
	VexNode list[MAXVEX];	//顶点表节点数组
	int vexnum,egdenum;  //顶点数和边数
} AdjList; //邻接表

void InitAdjList(AdjList* M)//初始化邻接表
{
   
	printf("输入顶点数和边数:");
	scanf("%d%d",&(M->vexnum),&(M->egdenum));
	fflush(stdin);
	printf("输入顶点:");
	for(int i = 0; i<M->vexnum; i++)
	{
   
		scanf("%c",&(M->list[i].vex));
		M->list[i].firstedge = NULL;  //将边表制空
	}
	fflush(stdin);
	for(int i = 0; i<M->egdenum; i++)//输入边
	{
   
		printf("输入边(Vi,Vj)的下标i,j和该边权值w:");
		int l,r;
		EdgeType w;
		scanf("%d%d%d",&l,&r,&w);

		EdgeNode* edge;

		edge = (EdgeNode*)malloc(sizeof(EdgeNode));//头插法
		edge->index = r;//记录下标
		edge->weight = w;
		edge->next = M->list[l].firstedge;
		M->list[l].firstedge = edge;

//		edge = (EdgeNode*)malloc(sizeof(EdgeNode));//无向图
//		edge->index = l;
//		edge->weight = w;
//		edge->next = M->list[r].firstedge;
//		M->list[r].firstedge = edge;
	}
}

void Print(AdjList* M)//展示
{
   
	for(int i = 0; i<M->vexnum; i++)
	{
   
		printf("%c:\n",M->list[i].vex);
		EdgeNode *p = M->list[i].firstedge;
		while(p)
		{
   
			printf("_%c -> %c = %d\n",M->list[i].vex,M->list[p->index].vex,p->weight);
			p = p->next;
		}
	}
}

int main()
{
   
    AdjList *M = (AdjList*
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值