数据结构--图

一.图的定义和术语

在这里插入图片描述
完全图任意两个点都有一个边相连
在这里插入图片描述
稀疏图 有很少边或弧的图(e<nlogn)
稠密图 有较多边或弧的图
边或弧带权的图
邻接 有边或弧相连,两个顶点的关系
关联 边或弧与顶点的关系
顶点的度 与该顶点相关联的边的数目
有向图中,顶点的度等于该顶点的出度和入度之和
在这里插入图片描述
路径 接续的边构成的顶点序列
路径长度 路径上边或弧的数目/权值之和
回路(环) 第一个顶点和最后一个顶点相同的路径
简单路径 除了路径起点终点可以相同,其余顶点均不相同的路径
简单回路(简单环) 除了路径起点和终点相同外,其余顶点均不相同的路径
连通图(强连通图) 在无向图(有向图)G中,若对任意两个顶点v,u都存在从v到u的的路径,那么就称G为连通图(强连通图)
在这里插入图片描述
权与网图中边或弧所具有的相关数称为权。表明从一个顶点到另一个顶点的距离或者耗费。
带权的图称为网
连通分量(强连通分量)
在这里插入图片描述
在这里插入图片描述
极小连通子图该子图是G的连通子图,在该子图中删除任何一个顶点子图不再连通。
生成树 包含无向图G所有顶点的极小连通子图
生成森林 对非连通图,由各个连通分量生成树的集合
在这里插入图片描述

二.图的抽象数据类型定义

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

三.图的存储结构

1. 邻接矩阵表示法

建立一个顶点表(记录各个顶点的信息)和一个邻接矩阵(表示各个顶点之间的关系)
在这里插入图片描述

  • 有向图的邻接矩阵表示法

在这里插入图片描述

  • 网(有权图)的邻接矩阵表示法
    在这里插入图片描述
    采用邻接矩阵表示法创建无向网

    1.输入总顶点数和总边数
    2.依次输入点的信息存入顶点表中
    3.初始化邻接矩阵,每个权值化为最大值
    4.构造邻接矩阵

//邻接矩阵的存储表示
#define n 100  //最大顶点数
#define maxint 32767       //表示极大值即无穷大
typedef char VerTexType;  //顶点的数据类型为字符型
typedef int ArcType;      //假设边的权值类型为整型

typedef struct
{
	VerTexType  vexs[n];   //顶点表
	ArcType arcs[n][n];    //邻接矩阵
	int vexnum;            //图当前的点数
	int arcnum;            //图当前的边数
}AMGraph;

//邻接矩阵表示法创建无向网
void CreateUDN(AMGraph* G)
{
	scanf("%d %d", &(G->vexnum), &(G->arcnum));
	//建立顶点表
	for (int i = 0; i < G->vexnum; i++)
	{
		scanf("%c ", G->vexs[i]);
	}
	//初始化邻接矩阵
	for (int i = 0; i < G->vexnum; i++)
	{
		for (int j = 0; j < G->vexnum; j++)
		{
			G->arcs[i][j] = maxint;   //边的权值均化为最大值
		}
	}
	for (int k = 0; k < G->arcnum; k++)
	{
		scanf(" %c %c",G->vexs[k], G->vexs[k + 1]);
		int w;
		scanf("%d", &w);
		int i, j;
		i = LocateVex(G, G->vexs[k]);
		j = LocateVex(G, G->vexs[k+1]);
		G->arcs[i][j] = w;
		G->arcs[i][j] = G->arcs[j][i];
	}
}
//查找顶点
int LocateVex(AMGraph G, VerTexType u)
{
	int i;
	for (i = 0; i < G.vexnum; i++)
	{
		if (u == G.vexs[i])
		{
			return i;
		}
	}
	return -1;
}
  • 无向图
    初始化邻接矩阵w均为0
    构造邻接矩阵w为1

  • 有向图
    邻接矩阵为非对称矩阵
    仅需为G.arcs[i][j]赋值,不需要给G.arcs[j][i]赋值

2.邻接矩阵

1.优点

  • 直观,简单,好理解
  • 方便检查任一顶点间是否存在边
  • 方便找任一顶点所有的邻接点(有边直接相连的顶点)
  • 方便计算任一顶点的度
    无向图中:对应行(列)非0元素的个数
    有向图中:对应行非0元素是出度,对应列非0元素是入度

2.缺点

  • 不利于增加和删除结点
  • 浪费空间 对于稀疏图来说,存有大量无效元素
  • 浪费时间 统计稀疏图中,有多少条边时

3.邻接表表示法(链式)

在这里插入图片描述
在这里插入图片描述

1.无向图的邻接表

在这里插入图片描述

1.邻接表不唯一
2.若无向图有n个顶点,e条边,则邻接表需要n个头结点和2e个表结点。适合存稀疏图。

2.有向图的邻接表

在这里插入图片描述
在这个图中,每个结点只存了出度边

  • 顶点Vi的出度为第i个单链表中的结点数
  • 顶点Vi的入度为整个单链表中邻接点值域是 i-1 的结点个数
    逆邻接表
    在这里插入图片描述
  • 顶点Vi的入度为第i个单链表中的结点数
  • 顶点Vi的出度为整个单链表中邻接点值域是 i-1 的结点个数

3.邻接表的代码实现

#define MVNum 100
#define VerTexType char  //假设顶点类型为char
//顶点的结点结构
typedef struct VNode
{
  VerTexType data;  //顶点信息
  ArcNode *firstarc;//指向第一条依附该顶点的边的指针
}VNode;
VNode AdjList[MVNum];//邻接表的类型为VNode
//边结点的结点结构
typedef struct ArcNode
{
    int adjvex;   //该边所指向的顶点的位置
    struct ArcNode*nextarc;//指向下一条边的指针
    OtherInfo info;    //和边相关的信息
}ArcNode;
//图的结构定义
typedef struct
{
   VNode vertices[MVNum];  //顶点数组
   int vexnum;   //图当前的顶点数
   int arcnum;   //弧数
}ALGraph;

邻接表操作举例说明:
在这里插入图片描述

   ALGragh G;
   G.vexum=5;
   G.arcnum=6;
   G.vertices[1].data='b';
   ArcNode*p=G.vertices[1].firtarc;   //p指向顶点b的第一条边结点
   p->adjvex=4;    //p指针指向的边结点是到下标为4结点的边

4.采用邻接表表示法创建无向图

1.算法思想

在这里插入图片描述

2.代码实现
void CreateUDG(ALGraph* G)
{
    scanf("%d %d", &(G->vexnum), &(G->arcnum));

   //构建表头结点表
    for (int i = 0; i < (G->vexnum); i++)
    {
      scanf(" %c", G->vertices[i].data);
      G->vertices[i].firstarc = NULL;
    }

    //构造邻接表
    for (int k = 0; k < (G->arcnum); k++)
    {
        VerTexType v1, v2;
        scanf(" %c %c", v1, v2);
        int i, j;
        i = LocateVex(G, v1);
        j = LocateVex(G, v2);
        ArcNode* p1 = (ArcNode*)malloc(sizeof(ArcNode));  //生成一个新的边结点p1
        p1->adjvex = j;         //邻接点序号为j
        //往下标为i的顶点加
        p1->nextarc = G->vertices[i].firstarc;
        G->vertices[i].firstarc = p1;
        ArcNode* p2 = (ArcNode*)malloc(sizeof(ArcNode));  //因为无向图生成另一个对称的新的边结点p2
        p2->adjvex = i;
        p2->nextarc = G->vertices[j].firstarc;
        G->vertices[j].firstarc = p2;
    }
}
 //查找结点,返回顶点表中结点的下标
 int LocateVex(ALGraph* G, VerTexType v)
 {
    for (int i = 0; i <(G->vexnum); i++)
    {
      if (G->vertices[i].data == v)
            return i;
    }
      return -1;
 }

5.邻接表特点

1.方便找任一顶点的所有邻接点
2.节约稀疏图的空间
3.方便计算顶点的度

4.邻接矩阵和邻接表表示的关系

在这里插入图片描述
2.区别:

  • 对于任意的无向图,邻接矩阵唯一,但邻接表不唯一
  • 邻接矩阵的空间复杂度为(n^2),邻接表的空间复杂度为O(n+e)
  • 故邻接矩阵多用于稠密图,邻接表多用于稀疏图
    在这里插入图片描述

5.十字链表

在这里插入图片描述在这里插入图片描述在这里插入图片描述

6.邻接多重表

在这里插入图片描述

四.图的遍历

(从已知连通图中某一顶点出发,沿着一些边访问图中所有顶点,并且每个顶点只被访问一次,叫做图的遍历)所以必须防止重复访问:设置visited辅助数组

1.深度优先搜索(DFS)Depth

1.思想

一条道走到黑
在这里插入图片描述

2.算法

1.邻接矩阵的无向图深度遍历实现
int visited[100] = { 0 };
void DFS(AMGraph* G, int v)
{
	visited[v] = 1;
	for (int w = 0; w < (G->vexnum); w++)
	{
		if ((G->arcs[v][w] != 0) && (visited[w] == 0))
			DFS(&G, w);
			//w为v的邻接点,如果w未访问,则递归调用DFS
	}
}
2.邻接表深度遍历实现

值得注意:从顶点表回去该链全部被访问完了之后,回到入口

3.分析

在这里插入图片描述

2.广度优先搜索(BFS)Breadth

在这里插入图片描述

跟树的层次遍历相似,利用到队列
在这里插入图片描述

3.DFS和BFS算法比较

  • 空间复杂度相同,都是O(n) 借用了栈或者队列
  • 时间复杂度只与存储结构(邻接矩阵O(n^2) 邻接表O(n+e) ) 与搜索路径DFS还是BFS无关

五.图的应用

1.最小生成树

1.生成树

所有顶点均由边连接在一起,但不存在回路的图

  • 一个图可以有不同棵生成树
  • 生成树的顶点个数与图的顶点个数相同
  • 生成树是图的最小连通子图
  • 生成树中任意两个顶点间路径是唯一的
  • 生成树含有n个顶点n-1条边

2.最小生成树–MST性质

在利用DFS或者BFS给定一个无向网络中,使得各边权值之和最小的生成树称为最小生成树,也叫最小代价生成树

  • MST性质
    在这里插入图片描述

    3.最小生成树的应用

  • 准备在n个城市间建立通信网,则n个城市应铺n-1条线路
    数学模型
    顶点–表示城市有n个,边–表示线路有(n-1)条,边的权值–表示线路的经济代价,连通网–表示n个城市间的通信网

4.构造最小生成树

1.Prim算法

在这里插入图片描述

2.Kruskal算法

在这里插入图片描述

3.两者比较

在这里插入图片描述

2.最短路径

1.典型案例

交通网络的应用–从甲地到乙地是否有公路连接?有多条通路情况下,哪一条最短?
交通网络用有向网络表示
顶点–表示地点
弧–表示两个地点有路连通
弧上面权值–表示两地之间的距离,交通费,途中花费的时间
最短路径问题:
如何让从甲地到乙地运输时间最短或者花费最少?
在这里插入图片描述

1.单源最短路径–Dijkstra算法

在这里插入图片描述
时间复杂度(n^2)

2.所有顶点间的最短路径–Floyd算法

加入顶点试探
在这里插入图片描述

3.针对有向无环图 AOV网,AOE网

在这里插入图片描述

1.拓扑排序(AOV网络)

AOV类似于上课顺序,表明某项活动有先决条件,所以不允许有回路
AOV网络的拓扑排序是不唯一的
在这里插入图片描述

检测AOV网络中是否存在环

对于有向图构造其顶点的拓扑有向序列,若网中所有顶点都在拓扑有序序列中,则AOV必不存在环

2.AOE网络–关键路径

1.例子

在这里插入图片描述

2.关键路径:

1.完成整项活动至少需要多少时间
2.哪些活动是影响工程进度的关键
关键路径-----路径最长的路径
路径长度-----路径上各活动持续时间之和
在这里插入图片描述
在这里插入图片描述
画了对号的即为关键路径

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值