返回

图之邻接表实现:简单、灵活的数据结构解析

前端





在计算机科学中,图是一种重要的数据结构,用于表示对象之间的关系。图由顶点和边组成,顶点表示对象,边表示对象之间的关系。图的实现有很多种,其中邻接表是一种简单且灵活的实现方式。

**邻接表的数据结构** 

邻接表由一个顶点数组和一个边数组组成。顶点数组存储图中的所有顶点,边数组存储图中的所有边。每个顶点数组元素都包含一个顶点值和一个指向该顶点所有邻接顶点的指针。每个边数组元素都包含两个顶点值和一个权值(如果边有权值的话)。

**邻接表的常见操作** 

邻接表可以进行多种操作,包括:

* 添加顶点:在图中添加一个新的顶点。
* 删除顶点:从图中删除一个顶点及其所有邻接边。
* 添加边:在图中添加一条新的边。
* 删除边:从图中删除一条边。
* 查找顶点:在图中查找一个顶点。
* 查找边:在图中查找一条边。
* 遍历图:访问图中的所有顶点或边。

**邻接表的实现** 

邻接表可以使用多种语言实现,例如C、C++、Java、Python等。这里以C语言为例,给出邻接表的基本实现:

```C
#include <stdio.h>
#include <stdlib.h>

// 定义顶点结构
typedef struct Vertex {
    int value;          // 顶点值
    struct Vertex *next;  // 指向下一个顶点的指针
} Vertex;

// 定义边结构
typedef struct Edge {
    int source;          // 边源顶点
    int destination;     // 边目标顶点
    int weight;         // 边权值
    struct Edge *next;   // 指向下一条边的指针
} Edge;

// 定义图结构
typedef struct Graph {
    int num_vertices;  // 顶点数
    int num_edges;     // 边数
    Vertex **vertices;  // 顶点数组
    Edge **edges;      // 边数组
} Graph;

// 创建一个新的图
Graph *create_graph() {
    Graph *graph = (Graph *)malloc(sizeof(Graph));
    graph->num_vertices = 0;
    graph->num_edges = 0;
    graph->vertices = (Vertex **)malloc(sizeof(Vertex *) * 100);  // 假设最多有100个顶点
    graph->edges = (Edge **)malloc(sizeof(Edge *) * 100);  // 假设最多有100条边
    return graph;
}

// 添加一个顶点到图中
void add_vertex(Graph *graph, int value) {
    Vertex *vertex = (Vertex *)malloc(sizeof(Vertex));
    vertex->value = value;
    vertex->next = NULL;
    graph->vertices[graph->num_vertices++] = vertex;
}

// 添加一条边到图中
void add_edge(Graph *graph, int source, int destination, int weight) {
    Edge *edge = (Edge *)malloc(sizeof(Edge));
    edge->source = source;
    edge->destination = destination;
    edge->weight = weight;
    edge->next = NULL;
    graph->edges[graph->num_edges++] = edge;
}

// 查找图中一个顶点
Vertex *find_vertex(Graph *graph, int value) {
    for (int i = 0; i < graph->num_vertices; i++) {
        if (graph->vertices[i]->value == value) {
            return graph->vertices[i];
        }
    }
    return NULL;
}

// 查找图中一条边
Edge *find_edge(Graph *graph, int source, int destination) {
    for (int i = 0; i < graph->num_edges; i++) {
        if (graph->edges[i]->source == source && graph->edges[i]->destination == destination) {
            return graph->edges[i];
        }
    }
    return NULL;
}

// 遍历图中所有顶点
void traverse_vertices(Graph *graph) {
    for (int i = 0; i < graph->num_vertices; i++) {
        printf("%d ", graph->vertices[i]->value);
    }
    printf("\n");
}

// 遍历图中所有边
void traverse_edges(Graph *graph) {
    for (int i = 0; i < graph->num_edges; i++) {
        printf("(%d, %d, %d) ", graph->edges[i]->source, graph->edges[i]->destination, graph->edges[i]->weight);
    }
    printf("\n");
}

// 释放图所占用的内存空间
void free_graph(Graph *graph) {
    for (int i = 0; i < graph->num_vertices; i++) {
        free(graph->vertices[i]);
    }
    free(graph->vertices);
    for (int i = 0; i < graph->num_edges; i++) {
        free(graph->edges[i]);
    }
    free(graph->edges);
    free(graph);
}

// 测试邻接表
int main() {
    Graph *graph = create_graph();

    add_vertex(graph, 1);
    add_vertex(graph, 2);
    add_vertex(graph, 3);
    add_vertex(graph, 4);
    add_vertex(graph, 5);

    add_edge(graph, 1, 2, 10);
    add_edge(graph, 1, 3, 20);
    add_edge(graph, 2, 4, 30);
    add_edge(graph, 3, 5, 40);
    add_edge(graph, 4, 5, 50);

    traverse_vertices(graph);
    traverse_edges(graph);

    Vertex *vertex = find_vertex(graph, 3);
    if (vertex != NULL) {
        printf("Vertex found: %d\n", vertex->value);
    }

    Edge *edge = find_edge(graph, 2, 4);
    if (edge != NULL) {
        printf("Edge found: (%d, %d, %d)\n", edge->source, edge->destination, edge->weight);
    }

    free_graph(graph);

    return 0;
}

邻接表的应用

邻接表广泛应用于各种领域,包括:

  • 社交网络:邻接表可以用来表示社交网络中的用户及其之间的关系。
  • 推荐系统:邻接表可以用来表示用户之间的相似度,从而为用户推荐感兴趣的物品。
  • 路由:邻接表可以用来表示网络中的路由器及其之间的连接,从而帮助数据包找到最佳的路径。
  • 最短路径:邻接表可以用来计算图中最短的路径,例如 Dijkstra 算法和 A* 算法。
  • 最小生成树:邻接表可以用来计算图中的最小生成树,例如 Kruskal 算法和 Prim 算法。

结语

邻接表是一种简单且灵活的图的数据结构,它可以用来表示各种各样的关系。邻接表具有存储结构简单、易于实现、操作方便等优点,因此在实际应用中得到了广泛的应用。