图的两种存储结构--邻接矩阵与邻接表

1.邻接矩阵

邻接矩阵就是使用一个二维矩阵表示图中顶点之间的边。
若是有权图,arcs[i][j] (0≤i, j<Nv; Nv为图中的顶点数)表示顶点i和j之间的边上权值,若i和j之间没有边,则将arcs[i][j]设置为INIFINITY(一个取不到的大值)。对于无向图,邻接矩阵满足:arcs[i][j] == arcs[j][i],它是一个方阵,而有向图的邻接矩阵不满足此特性,arcs[i][j]表示弧<Vi, Vj>的权,Vi为弧尾,Vj为弧头,即由Vi指向Vj。
若是无权图,可以把它当作边上权值是1的有权图,即若顶点i和j之间有边,则arcs[i][j] = 1,若顶点i和j之间没有边,则arcs[i][j] = 0。

#include <iostream>
using namespace std;

typedef char VertexType;	// 顶点类型,自定义成char
typedef int  WeightType;	// 边上的权值类型,自定义成int

#define MAXVEX	 (100)		// 最大顶点数
#define INFINITY (65535)	// 用65535表示∞,表示顶点之间没有边

typedef struct {
	VertexType vexs[MAXVEX];			// 顶点数组
	WeightType arcs[MAXVEX][MAXVEX];	// 邻接矩阵,二维矩阵,记录顶点间的连接情况,即边表
	int Nv, Ne;							// 图中顶点数和边数
} MGraph;

/* 建立图的邻接矩阵结构 */
void createMGraph(MGraph* G) {
	cout << "输入顶点数和边数:" << endl;
	cin >> G->Nv >> G->Ne;

	// 将邻接矩阵所有元素初始化为:INFINITY
	for (int i = 0; i < G->Nv; i++)
	{
		for (int j = 0; j < G->Nv; j++)
		{
			if (i == j)
			{
				G->arcs[i][j] = 0;	// 主对角线初始化为0
			}
			else
			{
				G->arcs[i][j] = INFINITY;
			}	
		}
	}

	cout << "输入顶点信息:" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		cin >> G->vexs[i];
	}

	// 读入Ne条边,建立邻接矩阵
	int i, j;
	WeightType w;
	for (int k = 0; k < G->Ne; k++)
	{
		cout << "输入边(vi, vj)的下标i、j及权值w:" << endl;
		cin >> i >> j >> w;
		G->arcs[i][j] = w;
		// G->arcs[j][i] = G->arcs[i][j];	// 无向图的邻接矩阵是对称阵,若G是有向图则不需要这行
	}
}

int main() {
	MGraph* G = new MGraph;
	createMGraph(G);

	// 打印顶点数组
	cout << "\n顶点数组" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		cout << G->vexs[i] << "\t";
	}

	// 打印邻接矩阵的值
	cout << "\n邻接矩阵" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		for (int j = 0; j < G->Nv; j++)
		{
			cout << G->arcs[i][j] << "\t";
		}
		cout << endl;
	}

	delete G;
}

运行结果:
以《大话数据结构》图7-4-4的有向图为例。
在这里插入图片描述

2.邻接表

邻接表使用链表来表示图中顶点之间的边。
将顶点Vi的所有邻接点链接成一个链表,然后在顶点数组的每个结点中设计一个指针,指向该链表,整体结构类似于哈希表。
顶点:按编号顺序将顶点数据存储在一维数组中
关联同一顶点的边(以顶点为尾的弧):用线性链表存储

#include <iostream>
using namespace std;

typedef char VertexType;	// 顶点类型,自定义成char
typedef int  WeightType;	// 边上的权值类型,自定义成int

#define MAXVEX	 (100)		// 最大顶点数

/* 边表结点 */
typedef struct EdgeNode {
	int			adjvex;		// 邻接点域,存储该顶点对应的下标
	WeightType	weight;		// 权值域,存储顶点权值,非网图(无权图)不必定义
	EdgeNode	*next;		// 指向下一个邻接点
} EdgeNode;

/* 顶点结点 */
typedef struct VertexNode {
	VertexType	data;			// 顶点域,存储顶点值
	EdgeNode	*firstEdge;		// 边表头指针,指向第一个邻接点
} VertexNode, AdjList[MAXVEX];	// AdjList表示邻接表类型

typedef struct {
	AdjList adjList;		// 邻接表,相当于:VertexNode adjList[MAXVEX];
	int Nv, Ne;				// 图中顶点数和边数
} ALGraph;

/* 建立图的邻接表结构 */
void createALGraph(ALGraph* G) {
	cout << "输入顶点数和边数:" << endl;
	cin >> G->Nv >> G->Ne;

	// 读入顶点信息
	cout << "输入顶点信息:" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		cin >> G->adjList[i].data;			// 读入顶点数值
		G->adjList[i].firstEdge = nullptr;	// 将边表指针置为空
	}

	// 读入Ne条边,建立邻接表
	int i, j;
	WeightType w;
	EdgeNode* e;
	for (int k = 0; k < G->Ne; k++)
	{
		cout << "输入边(vi, vj)的下标及i、j及权值w:" << endl;
		cin >> i >> j >> w;
		
		e = new EdgeNode;
		e->adjvex = j;						// 邻接点下标为j
		e->weight = w;						// 边(vi, vj)上的权值
		e->next = G->adjList[i].firstEdge;	// 将e的指针指向当前顶点指向的结点
		G->adjList[i].firstEdge = e;		// 将当前顶点的指针指向e
		/* 52、53这两行:使用头插法将结点插入链表中 */

		// 以下为无向图需要部分,有向图不需要 
		/*e = new EdgeNode;
		e->adjvex = i;
		e->weight = w;
		e->next = G->adjList[j].firstEdge;
		G->adjList[j].firstEdge = e;*/
	}
}

/* 销毁邻接表 */
void destroyAdjList(ALGraph* G) {
	for (int i = 0; i < G->Nv; i++)
	{
		while (G->adjList[i].firstEdge)
		{
			EdgeNode* e = G->adjList[i].firstEdge;
			G->adjList[i].firstEdge = e->next;
			delete e;
		}
	}
}

ostream& operator<<(ostream& os, VertexNode vex) {
	os << vex.data;
	return os;
}

int main() {
	ALGraph* G = new ALGraph;
	// 建图
	createALGraph(G);

	// 打印顶点数组
	cout << "\n顶点数组" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		cout << G->adjList[i].data << "\t";
	}

	// 打印邻接表的值
	cout << "\n邻接表" << endl;
	for (int i = 0; i < G->Nv; i++)
	{
		cout << "顶点" << G->adjList[i].data << "的邻接点有:";
		EdgeNode* p = G->adjList[i].firstEdge;
		while (p)
		{
			cout << G->adjList[p->adjvex] << "(" << p->weight << ")" << "\t";
			p = p->next;
		}
		cout << endl;
	}

	// 销毁邻接表
	destroyAdjList(G);
	
	delete G;
}

运行结果:
以《大话数据结构》图7-4-8的有向图为例。
在这里插入图片描述

3.参考链接

大话数据结构-程杰
青岛大学数据结构-王卓

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MinBadGuy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值