当前位置: 首页 > news >正文

图(邻接矩阵和邻接表)

一 图的概念

在 C++ 中,图(Graph)是一种表示 “多对多” 关系的数据结构,由 顶点(Vertex)和边(Edge)组成。顶点代表数据元素,边代表顶点间的连接关系。

  • 无向图:边没有方向(如社交网络中的好友关系),顶点 A 到 B 的边与 B 到 A 的边是同一根。
  • 有向图:边有方向(如地图中的单向道路),顶点 A 到 B 的边与 B 到 A 的边是两根不同的边。
  • 无权图:边没有权重(仅表示是否连通)。
  • 带权图:边有权重(如地图中道路的距离)。

在 C++ 中,图的存储主要有两种方式,选择取决于图的稀疏程度(边的多少)。

1. 邻接矩阵(适合稠密图)

用二维数组matrix[v][w]表示顶点 v 到 w 是否有边:

  • 无权图:matrix[v][w] = 1(有边)或0(无边)。
  • 带权图:matrix[v][w]存储边的权重(无边可用0表示)。

2. 邻接表(适合稀疏图)

用二维数组或数组加链表存储每个顶点的邻接顶点列表(带权图需存储权重)。每个顶点对应一个列表,列表中存储其直接连接的顶点。

二 邻接矩阵

1.邻接矩阵类的定义

//邻接矩阵类的定义
#define inf -1 //定义无效值class Graph {
private:int vertices; //顶点数量int** edges; //二维指针数组,用来存储边的信息public:Graph(int vertices); //构造函数,传入顶点个数~Graph(); //析构函数void addEdge(int u, int v, int w); //加边void printGraph(); //打印图的邻接矩阵
};

 首先定义无效值,表示两点之间没有边相连。邻接矩阵类包含成员属性:顶点数量和存储边信息的二维指针数组 以及 各个成员函数。

2.构造函数

//构造函数
Graph::Graph(int vertices) {this->vertices = vertices; //图有vertices个顶点edges = new int* [vertices]; //为二维指针数组(即邻接矩阵)分配内存for (int i = 0; i < vertices; ++i) {edges[i] = new int[vertices];for (int j = 0; j < vertices; ++j) {edges[i][j] = inf; //邻接矩阵每个元素初始值为inf(无效值)}}
}

 为二维指针数组分配vertices个顶点内存,通过循环为每个顶点分配vertices个内存。邻接矩阵每个元素初始化为inf(无效值)。

3.析构函数

//析构函数
Graph::~Graph() {for (int i = 0; i < vertices; ++i) { //释放邻接矩阵的内存delete[] edges[i];}delete[] edges;
}

通过循环释放邻接矩阵内存。

4.加边

//加边
void Graph::addEdge(int u, int v, int w) {//u表示边的起点,v表示边的终点,w表示边的权重edges[u][v] = w;
}

u表示边的起点,v表示边的终点,w表示边的权重。将w赋给邻接矩阵指定位置元素即可完成加边操作。

5.打印邻接矩阵

//打印图的邻接矩阵
void Graph::printGraph() { //打印邻接矩阵的元素值for (int i = 0; i < vertices; ++i) {for (int j = 0; j < vertices; ++j) {cout << edges[i][j] << " ";}cout << endl;}
}

通过两层循环打印邻接矩阵的元素值。

6.完整源码

#include<iostream>
using namespace std;//邻接矩阵类的定义
#define inf -1 //定义无效值class Graph {
private:int vertices; //顶点数量int** edges; //二维指针数组,用来存储边的信息public:Graph(int vertices); //构造函数,传入顶点个数~Graph(); //析构函数void addEdge(int u, int v, int w); //加边void printGraph(); //打印图的邻接矩阵
};//构造函数
Graph::Graph(int vertices) {this->vertices = vertices; //图有vertices个顶点edges = new int* [vertices]; //为二维指针数组(即邻接矩阵)分配内存for (int i = 0; i < vertices; ++i) {edges[i] = new int[vertices];for (int j = 0; j < vertices; ++j) {edges[i][j] = inf; //邻接矩阵每个元素初始值为inf(无效值)}}
}//析构函数
Graph::~Graph() {for (int i = 0; i < vertices; ++i) { //释放邻接矩阵的内存delete[] edges[i];}delete[] edges;
}//加边
void Graph::addEdge(int u, int v, int w) {//u表示边的起点,v表示边的终点,w表示边的权重edges[u][v] = w;
}//打印图的邻接矩阵
void Graph::printGraph() { //打印邻接矩阵的元素值for (int i = 0; i < vertices; ++i) {for (int j = 0; j < vertices; ++j) {cout << edges[i][j] << " ";}cout << endl;}
}

三 邻接表

1.邻接表类的定义

//邻接表类的定义
class Graph {
private:struct EdgeNode { //边结点结构体int vertex; //边指向的顶点int weight; //边的权重EdgeNode* next; //指向下一个边结点的指针};struct VertexNode { //顶点结构体int vertex; //顶点EdgeNode* fistEdge; //指向第一个边结点的指针};int vertices; //邻接表顶点个数VertexNode* nodes; //指针数组,存储所有顶点public:Graph(int vertices); //构造函数~Graph(); //析构函数void addEdge(int u, int v, int w); //加边void printGraph(); //打印邻接表
};

邻接表类中包含边结点结构体、顶点结构体、邻接表顶点个数、存储所有顶点的指针数组和各个成员函数。边结点结构体包含边指向的顶点编号、边的权重和指向下一个边结点的指针。顶点结构体包含顶点编号和指向第一个边结点的指针。

2.构造函数

//构造函数
Graph::Graph(int vertices) {this->vertices = vertices; //邻接表的顶点个数为传入值nodes = new VertexNode[vertices]; //为指针数组分配内存for (int i = 0; i < vertices; ++i) { nodes[i].vertex = i; //设置顶点编号nodes[i].fistEdge = nullptr; //由于还未加边,所以初始化指针指向空}
}

邻接表的顶点个数为传入值,为指针数组分配内存。通过循环设置每个顶点编号,由于还未加边,所以初始化指针指向空。

3.析构函数

//析构函数
Graph::~Graph() {//先逐个删除顶点的边结点链表for (int i = 0; i < vertices; ++i) { EdgeNode* curr = nodes[i].fistEdge;while (curr) {EdgeNode* temp = curr;curr = curr->next;delete temp;}}delete[] nodes; //最后释放数组内存
}

析构函数中先逐个删除顶点的边结点链表,最后释放数组内存。

4.加边

//加边
void Graph::addEdge(int u, int v, int w) {EdgeNode* newEdge = new EdgeNode; //创建一个新的边结点newEdge->vertex = v; //边指向vnewEdge->weight = w; //边权重为wnewEdge->next = nodes[u].fistEdge; //采用头插法将边加入到顶点u的边结点链表中nodes[u].fistEdge = newEdge;
}

首先创建一个新的边结点,接着让边指向顶点v,让边权重为w,然后采用头插法将边加入到顶点u的边结点链表中。

5.打印邻接表

//打印邻接表
void Graph::printGraph() {//遍历每个顶点,同时遍历每个顶点的邻接边链表for (int i = 0; i < vertices; ++i) {cout << "Vertex " << i << ": ";EdgeNode* curr = nodes[i].fistEdge;while (curr) {cout << curr->vertex << "(" << curr->weight << ") ";curr = curr->next;}cout << endl;}
}

遍历每个顶点,同时遍历每个顶点的邻接边链表。

6.完整源码

#include<iostream>
using namespace std;//邻接表类的定义
class Graph {
private:struct EdgeNode { //边结点结构体int vertex; //边指向的顶点int weight; //边的权重EdgeNode* next; //指向下一个边结点的指针};struct VertexNode { //顶点结构体int vertex; //顶点EdgeNode* fistEdge; //指向第一个边结点的指针};int vertices; //邻接表顶点个数VertexNode* nodes; //指针数组,存储所有顶点public:Graph(int vertices); //构造函数~Graph(); //析构函数void addEdge(int u, int v, int w); //加边void printGraph(); //打印邻接表
};//构造函数
Graph::Graph(int vertices) {this->vertices = vertices; //邻接表的顶点个数为传入值nodes = new VertexNode[vertices]; //为指针数组分配内存for (int i = 0; i < vertices; ++i) { nodes[i].vertex = i; //设置顶点编号nodes[i].fistEdge = nullptr; //由于还未加边,所以初始化指针指向空}
}//析构函数
Graph::~Graph() {//先逐个删除顶点的边结点链表for (int i = 0; i < vertices; ++i) { EdgeNode* curr = nodes[i].fistEdge;while (curr) {EdgeNode* temp = curr;curr = curr->next;delete temp;}}delete[] nodes; //最后释放数组内存
}//加边
void Graph::addEdge(int u, int v, int w) {EdgeNode* newEdge = new EdgeNode; //创建一个新的边结点newEdge->vertex = v; //边指向vnewEdge->weight = w; //边权重为wnewEdge->next = nodes[u].fistEdge; //采用头插法将边加入到顶点u的边结点链表中nodes[u].fistEdge = newEdge;
}//打印邻接表
void Graph::printGraph() {//遍历每个顶点,同时遍历每个顶点的邻接边链表for (int i = 0; i < vertices; ++i) {cout << "Vertex " << i << ": ";EdgeNode* curr = nodes[i].fistEdge;while (curr) {cout << curr->vertex << "(" << curr->weight << ") ";curr = curr->next;}cout << endl;}
}

相关文章:

  • 质心均匀体(引力屏蔽技术)
  • [ctfshow web入门] web68
  • Android 使用Paging3 实现列表分页加载、下拉刷新、错误重试、筛选功能
  • Java 泛型(Generic)
  • 基于NI-PXI的HIL系统开发
  • matlab介绍while函数
  • 从爬虫到网络---<基石9> 在VPS上没搞好Docker项目,把他卸载干净
  • CSS弹性布局
  • 最大公约数gcd和最小公倍数lcm
  • Yocto是如何使用$D目录来构建文件系统的?
  • 2025年货运从业资格考试题库及答案
  • comfyu BiRefNet-General模型下载及存放地方
  • JDK10新特性
  • 数据结构算法习题通关:树遍历 / 哈夫曼 / 拓扑 / 哈希 / Dijkstra 全解析
  • 小程序初始化加载时间优化 步骤思考与总结
  • 每日一题:两个仓库的最低配送费用问题
  • 每日一题洛谷T534125 合数c++
  • 深入理解Embedding技术-什么是Embedding?
  • 回文数(9)
  • RocketMQ Kafka区别
  • 邯郸一酒店办婚宴发生火灾,新郎母亲:饭没吃成酒店还要收费
  • 2025中国南昌国际龙舟赛5月23日启幕,是历年来南昌举办的最高规格龙舟赛事
  • 稳住外贸基本盘,这个中部大省出手了
  • 外卖员投资失败负疚离家流浪,经民警劝回后泣不成声给父母下跪
  • 如此城市|上海老邬:《爱情神话》就是我生活的一部分
  • 毗邻三市人均GDP全部超过20万元,苏锡常是怎样做到的?