ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

浙大数据结构 第六讲 图(上)

2021-12-10 23:35:28  阅读:219  来源: 互联网

标签:连通 int Graph 第六 浙大 BFS 顶点 数据结构 Nv


6.1 什么是图

图表示“多对多”的关系

图包含:

  1. 一组顶点:通常用V(Vertex)表示顶点集合
  2. 一组边:通常用E(Edge)表示边的集合
    边是顶点对:(v,w)∈E,其中v,w ∈ V
    有向边<v,w>表示从v指向w的边(单行线)
    不考虑重边和自回路
    在这里插入图片描述
    在这里插入图片描述

抽象数据类型定义

类型名称:图(Graph)
数据对象集:G(V,E)由一个非空的有限顶点集合V和一个有限边集合E组成。
操作集:对于任意图G ∈ Graph,以及v ∈ V,e ∈ E

Graph Create();//建立并返回空图
Graph InsertVertex(Graph G,Vertex V);//将一个顶点v插入G
Graph InsertEdge(Graph G,Edge e);//将一条边e插入G
void DFS(Graph G,Vertex V);//从顶点V出发优先遍历图G
void BFS(Graph G,Vertex V);//从顶点V出发宽度优先遍历图G
void ShortestPath(Graph G,Vertex V,int Dist[]);//计算图G中顶点v到任意其他顶点的最短距离
void MST(Graph G);//计算图G的最小生成树 

怎么在程序中表示一个图

邻接矩阵

在这里插入图片描述
在这里插入图片描述
邻接矩阵——有什么好处?

  1. 直观、简单、好理解
  2. 方便检查任意一堆顶点间是否存在边
  3. 方便找任一顶点的所有“邻接点”(有边直接相连的顶点)
  4. 方便计算任一顶点的“度”(从该点发出的边数为“出度”,指向该点的边数为“入度”)
    无向图:对应行(或列)非0元素的个数
    有向图:对应行非0元素的个数是“出度”,对应列非0元素的个数是“入度”

邻接矩阵——有什么坏处?

  1. 浪费空间——存稀疏图(点很多而边很少),有大量无效元素,但对稠密图(特别是完全图)还是很合算的
  2. 浪费时间——统计稀疏图中一共有多少条边

邻接表

邻接表:G[N]为指针数组,对应矩阵每行一个链表,只存非0元素
在这里插入图片描述
好处:

  1. 方便找任一结点的所有“邻接点”
  2. 节约稀疏图的空间:需要N个头指针 + 2E个结点(每个结点至少2个域)
  3. 方便计算无向图中任一结点的“度”

不足:

  1. 对无向图,只能计算“出度”;需要构造“逆邻接表”(存指向自己的边)来方便计算“入度”
  2. 不方便检查任意一对顶点间是否存在边

课后练习

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

在这里插入图片描述

6.2 图的遍历

深度优先搜索(Depth First Search,DFS)

例题引入:点亮视线范围内的一盏灯,当视线内的灯全部点亮时原路返回
在这里插入图片描述

void DFS(Vertex V)
{
	visited[V] = true;
	for(V的每个邻接点W)
		if(!visited[W]) DFS(W);
}

若有N个顶点、E条边,时间复杂度是
用邻接表存储图,有O(N+E)
用邻接矩阵存储图,有O(N^2)

广度优先搜索(Breadth First Search,BFS)

与树的层序遍历思路类似

void BFS(Vertex V)
{
	visited[V] = true;
	Enqueue(V,Q);
	while(!Isempty(Q))
	{
		V = Dequeue(Q);
		for( V 的每个邻接点 W )
			if(!visited[W])
			{
				visited[W] = true;
				Enqueue(W,Q);
			}
	}
}

若有N个顶点、E条边,时间复杂度是
用邻接表存储图,有O(N+E)
用邻接矩阵存储图,有O(N^2)

两种遍历方法的比较

在这里插入图片描述
在这里插入图片描述
讨论6.2 把迷宫出口换到哪里就该BFS不爽了?
右下角。BFS需要访问几乎所有节点才可以访问到出口。

总结

BFS是围绕某个点一层一层的进行遍历,借助队列的数据结构实现。
DFS是从一个点出发一直往深处遍历,条件不符就折返,通过栈的数据结构实现。
在正常情况下二者的时间复杂度都是相同的O(v+e),但是在内存的使用上BFS由于要使用队列存储所有的外层节点,所以内存消耗相对较大。

从宏观上来看:
如果你已经知道解离根节点比较近,那么BFS更好
如果整体上每个节点的边很多,那么BFS消耗的内存会很大
如果一棵树很深而解很少,那么DFS可能会很慢(相反如果解很多并且都比较深的话,那么BFS就会很慢)从名字上就很容易得出,
如果一个问题深度无穷而广度有限,那么DFS就没法获得解,但BFS可以,反之也同理。
BFS具有时间优势,因为它不用走回头路,DFS具有空间优势,因为同等情况下,DFS只保存了这一条路线的数据

图连不通怎么办?

连通: 如果从v到w存在一条(无向)路径,则称v和w是连通的。
路径: v到w的路径是一系列顶点{V,v1,v2,...,vn,W}的集合,其中任一对相邻的顶点间都有图中的边。路径的长度是路径中的边数(如果带权,则是所有边的权重和)。如果v到w之间的所有顶点都不同,则称简单路径
回路:起点等于终点的路径
连通图:图中任意两顶点均连通
连通分量:无向图的极大连通子图
极大顶点数:再加1个顶点就不连通了
极大边数:包含子图中所有顶点相连的所有边
在这里插入图片描述
对于无向图
强连通: 有向图中顶点V和W之间存在双向路径,则称V和W是强连通的
强连通图:有向图中任意两顶点均强连通
强连通分量:有向图的极大强连通子图
在这里插入图片描述
后两个图为G的强连通分量
在这里插入图片描述
ListComponents能够遍历 不连通的图 上所有结点

练习题
在这里插入图片描述
在这里插入图片描述

小白专场:建立一个图

建立邻接矩阵图

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
typedef struct GNode* PtrToGNode;
typedef struct ENode* PtrToENode;
typedef PtrToGNode MGraph;//以邻接矩阵存储的图类型
typedef PtrToENode Edge;
typedef int WeightType;
typedef int Vertex;
const int MaxVertexNum = 100;
struct GNode
{
	int Nv;//顶点数
	int Ne;//边数
	WeightType G[MaxVertexNum][MaxVertexNum];
};
struct ENode
{
	Vertex V1, V2;//有向边<V1,V2>
	WeightType Weight;//权重
};

MGraph CreateGraph(int VertexNum)
{
	Vertex V, W;
	MGraph Graph;
	Graph = (MGraph)malloc(sizeof(struct GNode));
	Graph->Nv = VertexNum;
	Graph->Ne = 0;
	for (int V = 0;V < Graph->Nv;V++)
	{
		for (int W = 0;W < Graph->Nv;W++)
		{
			Graph->G[V][W] = 0;
		}
	}
	return Graph;
}
void InsertEdge(MGraph Graph, Edge E)
{
	Graph->G[E->V1][E->V2] = E->Weight;
	Graph->G[E->V2][E->V1] = E->Weight;//若是无向图,还要插入边<V2,V1>
}
MGraph BuildMGraph()
{
	MGraph Graph;
	Edge E;
	Vertex V;
	int Nv, i;
	scanf("%d", &Nv);
	Graph = CreateGraph(Nv);
	scanf("%d", &Graph->Ne);
	if (Graph->Ne != 0)
	{
		E = (Edge)malloc(sizeof(struct ENode));
		for (i = 0;i < Graph->Ne;i++)
		{
			scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
			InsertEdge(Graph, E);
		}
	}
	/*如果顶点有数据的话,读入数据
	for (int V = 0;V < Graph->Nv;V++)
		scanf(" %c", &Graph->Data[V]);*/
	return Graph;
}

简化版(考试专用)

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int MAXN = 1000;
int G[MAXN][MAXN], Nv, Ne;
void BulidGraph()
{
	scanf("%d", &Nv);
	for (int i = 0;i < Nv;i++)
		for (int j = 0;j < Nv;j++)
			G[i][j] = 0;
	scanf("%d", &Ne);
	int v1, v2, w;
	for (int i = 0;i < Ne;i++)
	{
		scanf("%d %d %d", &v1, &v2, &w);
		G[v1][v2] = 1;
		G[v2][v1] = 1;
	}
}

标签:连通,int,Graph,第六,浙大,BFS,顶点,数据结构,Nv
来源: https://www.cnblogs.com/zjq182/p/15674211.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有