【数据结构】C++实现之图结构(一)

1.基本概念

1)图是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),G表示一个图,V是图G的顶点的集合,E是图G边的集合
2)顶点(Vertex):图中的数据元素,线性表中我们把数据元素叫元素,树中将数据元素叫结点。
3):顶点之间的逻辑关系用边来表示,边集可以是空的。
4)图分为两种有向图无向图
5)无向边(Edge):若顶点V1到V2之间的边没有方向,则称这条边为无向边,用(v1,v2)表示
6)无向图(Undirected graphs):图中任意两个顶点之间的边都是无向边(A,D)=(D,A)
7)有向边:若从顶点V1到V2的边有方向,则称这条边为有向边,也称弧(Arc)。用<V1,V2>表示,V1为狐尾(Tail),V2为弧头(Head)且<V1,V2>≠<V2,V1>
8)有向图(directed graphs):图中任意两个顶点之间的边都是有向边,注意:无向边用“()”,而有向边用“< >”表示
在这里插入图片描述
9)简单图:图中不存在顶点到其自身的边,且同一条边不重复出现
在这里插入图片描述
10)无向完全图:无向图中,任意两个顶点之间都存在边
11)有向完全图:有向图中,任意两个顶点之间都存在方向互为相反的两条弧
12)稀疏图:有很少条边;稠密图:有很多条边 【相对的概念】
13)权(Weight):与图的边或弧相关的数
14)网(Network):带权的图
15)子图(Subgraph):假设G=(V,{E})和G‘=(V’,{E’}),如果V’包含于V且E’包含于E,则称G’为G的子图
在这里插入图片描述
16)度(Degree)无向图中,与顶点V相关联的边的数目。有向图中,入度表示指向自己的边的数目,出度表示指向其他边的数目,该顶点的度等于入度与出度的和
17)路径的长度:一条路径上边或弧的数量
18)连通图:无向图中任意两个顶点都是连通的;图中的极大连通子图称为连通分量;
19)强连通图:有向图中对于任意顶点n,m均存在m到n以及n到m的路径,就称图为强连通图;其中图中的极大连通子图称为强连通分量
20)连通图的生成树:是一个连通子图且满足连通n个顶点,有n-1条边
21)有向树:有向图中一顶点入度为0,其余顶点入度为1。有向树是由多条有向就构成的森林
在这里插入图片描述

2. 图的抽象数据类型

在这里插入图片描述

3. 图的存储结构

3.1 邻接矩阵
在这里插入图片描述
https://blog.csdn.net/daijin888888/article/details/73177325

#define MAXVEX 100 /* 最大顶点数,应由用户定义 */
#define INFINITY 65535

typedef int Status;	/* Status是函数的类型 */
typedef char VertexType; /* 顶点类型应由用户定义  */
typedef int EdgeType; /* 边上的权值类型应由用户定义 */

struct MGraph
{
	VertexType vexs[MAXVEX];	 /* 顶点数组 */
	EdgeType arc[MAXVEX][MAXVEX];	/* 邻接矩阵,可看作边表 */
	int numNodes, numEdges; 	/* 图中当前的顶点数和边数  */
};

/* 建立无向网图的邻接矩阵表示 */
void CreateMGraph(MGraph *G)
{
	int i,j,k,w;
	cout<<"输入顶点数和边数"<<endl;
	scanf("%d,%d",&G->numNodes,&G->numEdges); 	/* 输入顶点数和边数 */
	
	for(i = 0;i <G->numNodes;i++) 					/* 读入顶点信息,建立顶点表 */
		scanf(&G->vexs[i]);
		
	for(i = 0;i <G->numNodes;i++)
		for(j = 0;j <G->numNodes;j++)
			G->arc[i][j]=INFINITY;	/* 邻接矩阵初始化 */
	for(k = 0;k <G->numEdges;k++) /* 读入numEdges条边,建立邻接矩阵 */
	{
		printf("输入边(vi,vj)上的下标i,下标j和权w:\n");
		scanf("%d,%d,%d",&i,&j,&w); /* 输入边(vi,vj)上的权w */
		G->arc[i][j]=w; 
		G->arc[j][i]= G->arc[i][j]; /* 因为是无向图,矩阵对称 */
	}
}
//n 个顶点和e 条边的无向网图的创建,时间复杂度为O(n+n^2+e) , 其中对邻接矩阵的初始化耗费了O(n^2)的时间

3.2 邻接表
1)对于顶点较少的图,采用就邻接矩阵方式太浪费空间,特别是稀疏有向图。所以可以考虑用链表来按需存储。数组与链表相结合的存储方法称为邻接表。
2)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便。另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息。
3)图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点vi 的边表,有向图则称为顶点vi作为弧尾的出边表。
在这里插入图片描述
4)带权值的邻接表
在这里插入图片描述
5)有向图邻接表与逆邻接表,方便计算图顶点的入度或者出度
在这里插入图片描述

//邻接表
typedef char VertexType; /* 顶点类型应由用户定义 */
typedef int EdgeType; /* 边上的权值类型应由用户定义 */

struct EdgeNode /* 边表结点  */
{
	int adjvex;    /* 邻接点域,存储该顶点对应的下标 */
	EdgeType info;		/* 用于存储权值,可以不需要 */
	EdgeNode *next; /* 链域,指向下一个邻接点 */
};

struct VertexNode /* 顶点表结点 */
{
	VertexType data; /* 顶点域,存储顶点信息 */
	EdgeNode *firstedge;/* 边表头指针 */
} ;
typedef VertexNode AdjList[MAXVEX];   //定义AdjList数据类型

struct GraphAdjList
{
	AdjList adjList;
	int numNodes, numEdges; /* 图中当前顶点数和边数 */
};

/*建立无向图的邻接表结构 */
void  CreateALGraph(GraphAdjList *G)
{
	int i, j, k;
	EdgeNode *e;
	cout << "输入顶点数和边数" << endl;
	scanf("%d,%d", &G->numNodes, &G->numEdges); /* 输入顶点数和边数 */
	for (i = 0; i < G->numNodes; i++) /* 读入顶点信息,建立顶点表 */
	{
		scanf(&G->adjList[i].data); 	/* 输入顶点信息 */
		G->adjList[i].firstedge = NULL; 	/* 将边表置为空表 */
	}

	for (k = 0; k < G->numEdges; k++)/* 头插法建立边表 */
	{
		cout << "输入边(vi,vj)上的顶点序号" << endl;
		scanf("%d,%d", &i, &j); /* 输入边(vi,vj)上的顶点序号 */
		e = new EdgeNode; /* 向内存申请空间,生成边表结点 */
		e->adjvex = j;						/* 邻接序号为j */
		e->next = G->adjList[i].firstedge;	/* 将e的指针指向当前顶点上指向的结点 */
		G->adjList[i].firstedge = e;		/* 将当前顶点的指针指向e */

		e = new EdgeNode ;					/* 向内存申请空间,生成边表结点 */
		e->adjvex = i;						/* 邻接序号为i */
		e->next = G->adjList[j].firstedge;	/* 将e的指针指向当前顶点上指向的结点 */
		G->adjList[j].firstedge = e;		/* 将当前顶点的指针指向e */
	}
}

3.3 十字链表法(主要针对有向图设计)
1)由于有向图在邻接表中关心出度,却不了解入度;同时若关心入度却不了解出度,因此提出了十字链表法来解决
2)什么是十字链表,就是利用纵链存储各个顶点的入度,横链存储各顶点出度
在这里插入图片描述

//十字链表
struct EdgeNode //有向图边的数据结构  
{
	int startvex;    //弧起点顶点
	int endvex;     //弧终点顶点
	EdgeNode *startlink; //入边的起点指针域
	EdgeNode *endlink;   //出边的终点指针域
};


//十字链表
struct EdgeNode //有向图边的数据结构  
{
	int startvex;    //弧起点顶点
	EdgeNode *startlink; //起点顶点的出度指针域

	int endvex;     //弧终点顶点
	EdgeNode *endlink;   //终点的入度指针域
};

struct VertexNode //有向图顶点数据结构
{
	VertexType data;	//顶点域,存储顶点信息
	EdgeNode *firstin;	//顶点的第一个入度指针域
	EdgeNode *firsrout; //顶点的第一个出度指针域
};
typedef VertexNode AdjList[MAXVEX];   //定义AdjList数据类型

struct GraphAdjList
{
	AdjList adjList;
	int numNodes, numEdges; /* 图中当前顶点数和边数 */
};

3.4 邻接多重表(主要针对无向图设计)
3.5 边集数组
边集数组是由两个- -维数组构成。-个是存储顶点的信息;另一个是存储边的信息,这个边数组每个数据元素由- -条边的起点下标(begin)、 终点下标(end) 和权(weight)组成。
在这里插入图片描述

4. 图的遍历

从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历
4.1 深度优先遍历(DFS)
它从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v 有路径相通的顶点都被访问到
在这里插入图片描述
4.2 广度优先遍历
如果说图的深度优先遍历类似树的前序遍历, 那么图的广度优先遍历就类似于树的层序遍历了。
在这里插入图片描述

5. 最小生成树

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值