一、图的定义,邻接矩阵和邻接表的实现

目录

一、初识图

(1)图的定义

(2)图的分类

二、图的存储结构

(1)邻接矩阵

(2)邻接表(无向图)

(3)其他


一、初识图

(1)图的定义

         图(Graph)是由顶点的有穷非空集合(必须存在顶点)和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合

(2)图的分类

        若顶点到顶点之间的边设有方向,则称这条边为无向边。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图

        若顶点到顶点的边有方向,则称这条边为有向边,也称为弧。如果图中任意两个顶点之间的边都是有向边,则称该图为有向图

 除此之外还有:

  • 简单图
  • 无向完全图
  • 有向完全图
  • 稠密图
  • 带权图(网)
  • ...

二、图的存储结构

(1)邻接矩阵

        图的邻接矩阵存储方式是用二维数组来表示图,我们来看一个实例

       它的邻接矩阵为:

        简单解释一下,对于矩阵的主对角线的值,即arc[0][0]、arc[1][1]、arc[2[2]、arc[3][3],全为0是因为不存在顶点到自身的边,比如v_{0}v_{0}。arc[0][1]=1是因为v_{0}v_{1}的边存在,而arc[1][3]=0是因为v_{1}v_{3}的边不存在。并且由于是无向图,v_{1}v_{3}的边不存在,意味着v_{3}v_{1}的边也不存在。所以无向图的边数组是一个对称矩阵。

        有了这个矩阵,我们就可以很容易地知道图中的信息。

  1. 我们要知道某个顶点的度,其实就是这个顶点在邻接矩阵中第ⅰ行(或第i列)的元素之和。比如顶点1的度就是1+0+1+0=2。
  2. 求顶点M的所有邻接点就是将矩阵中第i行元素扫描一遍,arc[i][j]为1就是邻接点。

        有向图的邻接矩阵也是一样

        而如果是带权图的话,如果两个顶点可达,那么我们就将arc[i][j]的1变为他们两点之间的权值,如果两个顶点之间不可达,那么我们就将arc[i][j]的0变为无穷大。这里需要注意自己到自己的权值为0。

 邻接矩阵(无向图)的实现:

#include<iostream>
using namespace std;

#define MAXVEX 100//最大顶点数
typedef char VertexType;//顶点类型
typedef int EdgeType;//边上的权值类型
typedef struct
{
	VertexType vexs[MAXVEX];//顶点表
	EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵
	int numVertexte;//当前顶点数
	int numEdges;//当前边数
}MGraph;

void CreateMGraph(MGraph* G)//建立无向网图的邻接矩阵表示
{
	int i, j, k, w;
	cout << "请输入顶点数和边数:" << endl;
	cin >> G->numVertexte >> G->numEdges;
	for ( i = 0; i < G->numVertexte; ++i)//读入顶点信息,建立顶点表
	{
		cin >> G->vexs[i];
	}

	for (i = 0; i < G->numVertexte; ++i)
	{
		for ( j = 0; j < G->numVertexte; ++j)
		{
			G->arc[i][j] = INT_MAX;//邻接矩阵初始化
		}
	}

	for (k = 0; k < G->numEdges; ++k)
	{
		cout << "输入边(vi,vj)上的下标i,下标 j 和权 w:" << endl;
		cin >> i >> j >> w;
		G->arc[i][j] = w;
		G->arc[j][i] = G->arc[i][j];
	}
}

int main()
{
	MGraph G;
	CreateMGraph(&G);
	return 0;
}

(2)邻接表(无向图)

        邻接矩阵是不错的一种图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费的。于是引出了链式存储的结构。

        邻接表的处理办法是这样。

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

例如

无向图的邻接表

 有向图的邻接表

 对于带权值的网图

邻接表(无向图)的实现

#include<iostream>
using namespace std;

#define MAXVEX 100//最大顶点数
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;//当前顶点数
	int numEdges;//当前边数
}GraphAdjList;

void CreateALGraph(GraphAdjList* G)//建立无向网图的邻接矩阵表示
{
	int i, j, k;
	EdgeNode* e;
	cout << "请输入顶点数和边数:" << endl;
	cin >> G->numVertexes >> G->numEdges;
	for ( i = 0; i < G->numVertexes; ++i)//读入顶点信息,建立顶点表
	{
		cin >> G->adjList[i].data;
		G->adjList[i].firstedge = nullptr;
	}

	for (k = 0; k < G->numEdges; ++k)//建立邻接表
	{
		cout << "输入边(vi,vj)上的顶点序号:" << endl;
		cin >> i >> j;
		e = new EdgeNode;
		e->adjvex = j;
		e->next = G->adjList[i].firstedge;
		G->adjList[i].firstedge = e;//头插法

		e = new EdgeNode;
		e->adjvex = i;
		e->next = G->adjList[j].firstedge;
		G->adjList[j].firstedge = e;//头插法
	}
}

int main()
{
	GraphAdjList G;
	CreateALGraph(&G);
	return 0;
}

(3)其他

        除上述两种方法之外,图的存储方式还有十字链表,邻接多重表,边集数组等。

猜你喜欢

转载自blog.csdn.net/ThinPikachu/article/details/123596002