图是由节点(顶点)和连接节点的边组成的一种非线性数据结构。它用于表示不同对象之间的关系或网络结构。图可以用于建模和解决许多现实世界中的问题,例如社交网络分析、路线规划、图像处理等。
在图中,节点表示实体或对象,而边表示节点之间的关系。边可以是有向的(具有方向)或无向的(没有方向),并可以具有权重或标签来表示边的属性或距离。
有几种常见的图数据结构,包括:
- 邻接矩阵(Adjacency Matrix):邻接矩阵是一个二维数组,用于表示图中节点之间的连接关系。矩阵的行和列分别代表图中的节点,矩阵元素表示节点之间的边或连接。如果节点 i 和节点 j 之间有边存在,则邻接矩阵的 (i, j) 位置上的值为 1 或权重值,否则为 0 或表示不存在的标记。邻接矩阵适用于稠密图,但对于大型稀疏图来说会占用较多的内存空间
- 邻接列表(Adjacency List):邻接列表使用链表或数组的列表来表示节点及其相邻节点的关系。每个节点都有一个列表,列出与其直接相连的节点。邻接列表适用于稀疏图,因为它只需要存储节点的相邻节点信息,可以节省内存空间。
- 关联矩阵(Incidence Matrix):关联矩阵使用二维矩阵表示节点和边之间的关系。矩阵的行代表节点,列代表边,矩阵元素表示节点和边之间的关联关系。如果节点 i 是边 j 的起点,则矩阵的 (i, j) 位置上的值为 1 或权重值,如果节点 i 是边 j 的终点,则该位置上的值为 -1。关联矩阵适用于有向图以及边有多个属性的图。
- 哈希表或字典(Hash Table or Dictionary):链表表示法是一种灵活的图数据结构,使用节点和边的链表来表示图。每个节点包含节点的信息以及指向其相邻节点的指针。边也可以作为链表节点的一部分存储。链表表示法适用于动态图或需要频繁地添加和删除节点和边的情况。
图的邻接矩阵
在C++中,可以使用二维数组来表示图的邻接矩阵。以下是一个简单的示例代码,展示了如何使用邻接矩阵表示有向图:
#include <iostream>
#include <vector>
// 定义图类
class Graph {
private:
int numVertices; // 图中的节点数
std::vector<std::vector<int>> adjacencyMatrix; // 邻接矩阵
public:
// 构造函数
Graph(int numVertices) : numVertices(numVertices) {
// 初始化邻接矩阵为全零
adjacencyMatrix.resize(numVertices, std::vector<int>(numVertices, 0));
}
// 添加边
void addEdge(int src, int dest) {
// 在邻接矩阵中设置边的连接关系
adjacencyMatrix[src][dest] = 1;
}
// 打印邻接矩阵
void printAdjacencyMatrix() {
for (int i = 0; i < numVertices; ++i) {
for (int j = 0; j < numVertices; ++j) {
std::cout << adjacencyMatrix[i][j] << " ";
}
std::cout << std::endl;
}
}
};
int main() {
// 创建一个包含5个节点的有向图
Graph graph(5);
// 添加边
graph.addEdge(0, 1);
graph.addEdge(0, 4);
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
// 打印邻接矩阵
graph.printAdjacencyMatrix();
return 0;
}
上述代码中,首先定义了一个Graph
类,其中包含私有成员变量numVertices
表示节点数,以及adjacencyMatrix
用于存储邻接矩阵。构造函数初始化邻接矩阵为全零。
通过addEdge
函数可以向图中添加边,该函数会在邻接矩阵中设置对应位置的值为 1 来表示节点之间的连接关系。
最后,通过printAdjacencyMatrix
函数可以打印邻接矩阵的内容。运行结果为:
0 1 0 0 1
0 0 1 1 0
0 0 0 1 0
0 0 0 0 1
0 0 0 0 0
请注意,上述代码只展示了有向图的邻接矩阵表示方法。如果需要表示无向图,可以将邻接矩阵设置为对称矩阵,即在设置边连接关系时同时设置两个对称位置的值为 1。
图的邻接表
在C++中,可以使用链表来实现图的邻接表。每个节点通过一个链表存储其相邻节点的信息。以下是一个简单的示例代码,展示了如何使用链表实现图的邻接表表示:
#include <iostream>
// 定义图节点的结构
struct Node {
int dest; // 相邻节点的目标
Node* next; // 指向下一个相邻节点的指针
};
// 定义图类
class Graph {
private:
int numVertices; // 图中的节点数
Node** adjacencyList; // 邻接表
public:
// 构造函数
Graph(int numVertices) : numVertices(numVertices) {
adjacencyList = new Node*[numVertices]();
// 初始化邻接表为空
for (int i = 0; i < numVertices; ++i) {
adjacencyList[i] = nullptr;
}
}
// 添加边
void addEdge(int src, int dest) {
// 创建新的节点
Node* newNode = new Node;
newNode->dest = dest;
newNode->next = nullptr;
// 将新节点插入到src节点的邻接列表头部
newNode->next = adjacencyList[src];
adjacencyList[src] = newNode;
// 对于无向图,还需插入反向边
newNode = new Node;
newNode->dest = src;
newNode->next = nullptr;
newNode->next = adjacencyList[dest];
adjacencyList[dest] = newNode;
}
// 打印邻接表
void printAdjacencyList() {
for (int i = 0; i < numVertices; ++i) {
Node* currentNode = adjacencyList[i];
std::cout << "顶点 " << i << " 的邻接列表: ";
while (currentNode != nullptr) {
std::cout << currentNode->dest << " ";
currentNode = currentNode->next;
}
std::cout << std::endl;
}
}
// 析构函数,释放内存
~Graph() {
for (int i = 0; i < numVertices; ++i) {
Node* currentNode = adjacencyList[i];
while (currentNode != nullptr) {
Node* nextNode = currentNode->next;
delete currentNode;
currentNode = nextNode;
}
}
delete[] adjacencyList;
}
};
int main() {
// 创建一个包含5个节点的无向图
Graph graph(5);
// 添加边
graph.addEdge(0, 1);
graph.addEdge(0, 4);
graph.addEdge(1, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
graph.addEdge(3, 4);
// 打印邻接表
graph.printAdjacencyList();
return 0;
}
以下是使用邻接表表示图的示例代码:
#include <iostream>
#include <vector>
class Graph {
private:
int numVertices; // 图中的节点数
std::vector<std::vector<int>> adjList; // 邻接表
public:
// 构造函数
Graph(int numVertices) : numVertices(numVertices) {
adjList.resize(numVertices);
}
// 添加边
void addEdge(int src, int dest) {
adjList[src].push_back(dest);
adjList[dest].push_back(src); // 对于无向图,需要添加反向的边
}
// 打印邻接表
void printGraph() {
for (int i = 0; i < numVertices; ++i) {
std::cout << "节点 " << i << " 的相邻节点:";
for (int neighbor : adjList[i]) {
std::cout << neighbor << " ";
}
std::cout << std::endl;
}
}
};
int main() {
// 创建一个包含5个节点的图
Graph graph(5);
// 添加边
graph.addEdge(0, 1);
graph.addEdge(0, 2);
graph.addEdge(1, 3);
graph.addEdge(2, 3);
graph.addEdge(2, 4);
graph.addEdge(3, 4);
// 打印邻接表
graph.printGraph();
return 0;
}
在上述代码中,我们定义了一个Graph
类来表示图。使用邻接表作为内部数据结构,使用std::vector<std::vector<int>> adjList
来存储图的邻接表,其中每个向量表示节点的相邻节点列表。
addEdge
函数用于向图中添加边,它将目标节点添加到源节点的相邻节点列表中,并对于无向图,还需要添加反向的边。
printGraph
函数用于打印图的邻接表。它遍历每个节点,并输出其相邻节点列表。
在示例代码中,我们创建了一个包含5个节点的图,并添加了一些边。然后,通过调用printGraph
函数,打印图的邻接表。
这种邻接表表示法对于稀疏图(边相对较少)非常高效,可以快速查找每个节点的相邻节点,并节省存储空间。