图的邻接表存储法:高效节省空间的图表示方法

目录

1. 前言

2. 邻接表存储法的原理

3. 邻接表存储法的优缺点

3.1 优点

3.2 缺点

4. 使用邻接表存储法解决实际问题

4.1 社交网络

4.2 路径查找算法

5. 实现邻接表存储法

5.1 邻接表存储结构定义

5.2 初始化

5.3 插入删除边操作 

6. 结论


1. 前言

        在图论中,图是一种常见的数据结构,用于表示各种实际问题中的关系。图的存储方法有多种,其中邻接表存储法是一种常用且高效的表示方法。本文将详细介绍图的邻接表存储法及其实现原理,同时分析其优缺点,并提供实际应用示例,以帮助读者深入了解和应用这一图表示方法。

2. 邻接表存储法的原理

        邻接表存储法是一种使用链表来表示图的结构,其核心思想是通过链表将与每个顶点相邻的顶点连接起来。对于图中的每个顶点,创建一个链表,链表中存储了与该顶点相邻的其他顶点。每个顶点结构包含两个字段:顶点的数据(通常是一个标识符或值)和指向第一个邻接边的指针(通常称为firstEdge)。

        在无向图中,如果顶点A与顶点B相邻,那么在邻接表中,A的链表中会有一个指向B的边结构,同时B的链表中也会有一个指向A的边结构。在有向图中,只有一个方向上有连接,即顶点A的链表中有一个指向B的边结构,而B的链表中没有指向A的边结构。

3. 邻接表存储法的优缺点

3.1 优点

        节省空间:对于稀疏图(边相对较少的图),邻接表存储法能够节省大量的内存空间,因为只存储实际存在的边,不需要占用多余的空间。
        方便查找:在查找与某个顶点相邻的所有顶点时,只需要遍历该顶点的邻接链表,不需要遍历整个矩阵,提高了查找效率。

3.2 缺点

        查找特定边较慢:在邻接表存储法中查找特定的边可能需要遍历整个邻接表,相对较慢,特别是对于稠密图。
        内存开销:对于稠密图,邻接表存储法可能会占用较多的内存空间,因为每个顶点都需要一个链表来存储邻接边。

4. 使用邻接表存储法解决实际问题

        邻接表存储法在实际问题中有广泛应用。以下是一些实际应用示例:

4.1 社交网络

        社交网络中的用户关系可以用无向图表示,每个用户是一个顶点,好友关系是一条边。使用邻接表存储法表示图后,可以方便地查找某个用户的好友列表,或者查找共同好友等信息。

4.2 路径查找算法

        例如广度优先搜索(BFS)和深度优先搜索(DFS)。在邻接表存储法中,使用BFS或DFS算法可以在图中查找两个顶点之间的最短路径或所有可能的路径。

5. 实现邻接表存储法

        为了更好地理解邻接表存储法,我们来实现一个简单的图的邻接表表示。下面是用C语言实现的示例代码:

5.1 邻接表存储结构定义

#define MAX_VERTICES 100
typedef int VertexType;

// 定义图的边结构
typedef struct Edge {
    int adjVertex;      // 与边相连的当前此顶点的索引
    Edge* next;  // 指向下一个邻接边的指针
} Edge;

// 定义图的顶点结构
typedef struct Vertex {
    VertexType data;               // 顶点数据
    Edge* firstEdge; // 指向第一个邻接边的指针
} Vertex;

// 定义图的邻接表结构
typedef struct Graph {
    int num_vertices,num_edges;     // 图中顶点的数量
    Vertex vertices[MAX_VERTICES];  // 存储顶点的数组
} Graph;

5.2 初始化

// 初始化图
void initGraph(Graph* graph, int num_vertices) {
    graph->num_vertices = num_vertices;
    for (int i = 0; i < num_vertices; ++i) {
        graph->vertices[i].data = i;  // 以顶点索引作为顶点数据
        graph->vertices[i].firstEdge = NULL; // 初始化顶点的邻接边链表为空
    }
}

5.3 插入删除边操作 

// 向图中插入一条边
void insertEdge(Graph* graph, int from, int to) {
    if (from >= 0 && from < graph->num_vertices && to >= 0 && to < graph->num_vertices) {
        // 创建新的边节点
        Edge* newEdge = (Edge*)malloc(sizeof(Edge));
        newEdge->adjVertex = to;
        newEdge->next = graph->vertices[from].firstEdge;

        // 更新顶点的邻接边链表
        graph->vertices[from].firstEdge = newEdge;
    }
}

// 删除图中的一条边
void deleteEdge(Graph* graph, int from, int to) {
    if (from >= 0 && from < graph->num_vertices && to >= 0 && to < graph->num_vertices) {
        Edge* prevEdge = NULL;
        Edge* currentEdge = graph->vertices[from].firstEdge;

        // 在from的邻接链表中查找与to相邻的边
        while (currentEdge != NULL && currentEdge->adjVertex != to) {
            prevEdge = currentEdge;
            currentEdge = currentEdge->next;
        }

        // 如果找到了与to相邻的边,进行删除操作
        if (currentEdge != NULL) {
            if (prevEdge != NULL) {
                // 删除中间或尾部的边节点
                prevEdge->next = currentEdge->next;
            }
            else {
                // 删除头部的边节点
                graph->vertices[from].firstEdge = currentEdge->next;
            }

            // 释放删除的边节点内存
            free(currentEdge);
        }

        // 如果是无向图,还需要在to的邻接链表中删除与from相邻的边
        // 此处省略代码,读者可以自行添加
    }
}

         其实,对用邻接表存储的图的操作,其实就是对一条条链表操作,每个顶点对应一条链表,这条链表上存储这个顶点所有有关联的顶点信息,其实也就是将此顶点的所有边给间接表示出来了,这就是邻接表的核心

        对用邻接表存储的图的其他操作,我会在后续在图的遍历与图的应用当中用到。


6. 结论

        图的邻接表存储法是一种高效节省空间的图表示方法,适用于稀疏图和需要频繁查找相邻顶点的场景。虽然它在查找特定边和内存开销方面存在一些缺点,但在实际应用中,通过合理选择存储结构和算法,可以充分发挥邻接表存储法的优势,解决各种实际问题。        

        通过本文的介绍,相信读者已经对图的邻接表存储法有了较深入的了解,可以在实际项目中灵活应用,提高算法效率,并优化内存空间的使用。

        总之,明确一点,将图中所有顶点存在一个Vertex vertices[MAX_VERTICES]数组中,这个顶点数组中,每个顶点元素都有一个用来存储两连顶点的链表,并且这个顶点元素就是它的链表的   “头“。操作图就是操作这个顶点数组与它们的链表。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
采用邻接表创建有向的步骤如下: 1. 创建一个顶点表,其中每个顶点包含一个数据域和指向第一条边的指针。可以使用数组和链表的方式来实现。 2. 对于有n个顶点的,可以使用一个循环来输入每个顶点的数据域。例如,使用一个字符数组来存储顶点的数据,然后循环输入每个顶点的值并将其保存到顶点表的对应位置。 3. 创建边表,即为每个顶点创建一个链表来存储与其相邻的边。可以使用一个循环来遍历顶点表,对于每个顶点,创建一个边表并将其指针保存到对应顶点的指针域中。 4. 输入有向的边信息。可以使用一个循环来输入每条边的起点和终点,并将其添加到对应顶点的边表中。 通过以上步骤,就可以采用邻接表创建一个有向了。具体的实现可以参考示例代码和详细介绍。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [2——利用邻接表创建有向](https://blog.csdn.net/baidu_36669549/article/details/89046876)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [邻接表创建有向](https://blog.csdn.net/qq_42169456/article/details/121244653)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [C++实现有向邻接表的构建](https://download.csdn.net/download/weixin_38638799/12725856)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

不想学习啊啊

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

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

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

打赏作者

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

抵扣说明:

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

余额充值