📌  相关文章
📜  UGC-NET | UGC-NET CS 2017年12月2日|问题10(1)

📅  最后修改于: 2023-12-03 15:35:27.180000             🧑  作者: Mango

UGC-NET | UGC-NET CS 2017年12月2日|问题10

问题10:

给定一个具有n个顶点和m个边的无向图G={V, E},其中V是顶点集合,E是边集合。请考虑使用以下数据结构维护图G,其中邻接表(adjacency list)和邻接矩阵(adjacency matrix)分别用AL和AM表示。

  1. 对于给定的图G,请编写一个算法,计算出在图G中使用邻接表AL表示时,AL需要占用的内存量(以字节为单位),并将结果存储在变量mem_AL中。

  2. 对于给定的图G,请编写一个算法,计算出在图G中使用邻接矩阵AM表示时,AM需要占用的内存量(以字节为单位),并将结果存储在变量mem_AM中。

  3. 关于问题1和问题2中的算法,请回答以下问题:

    a. 当n和m相同的时候,哪种表现更好,为什么?

    b. 当图G是非常稠密的时候,哪种表现更好,为什么?

答案:

  1. 计算邻接表AL需要占用的内存量

算法:(基于C++)

// 计算邻接表AL需要的内存量
int compute_mem_AL(int v, int e) {
    // 邻接表中v个顶点所需的结构体长度 + 所有边中的起始顶点和目标顶点所需的整形长度
    int struct_len = sizeof(struct node) + sizeof(int) * 2;
    int mem_AL = struct_len * v + sizeof(node*) * e;
    return mem_AL;
}

解释如下:

该算法基于C++,主要是计算邻接表占用的内存量。我们知道邻接表是使用链表来存储的,所以每个顶点的邻居节点使用一个链表来存储。结构体node包含了节点值和指向下一个节点的指针,每个链表项的结构体node占用的空间是sizeof(node)。在邻接表中存储所有边则需要一个指向邻居节点链表的指针数组,数组长度为边的个数e,每个指针占用的空间是sizeof(node*)。因此,算法中计算出内存占用量的公式为:

mem_AL = struct_len * v + sizeof(node*) * e

其中,struct_len = sizeof(struct node) + sizeof(int) * 2,在计算节点的内存占用量时,需要加上两个int类型的变量表示边的起始顶点和目标顶点。

  1. 计算邻接矩阵AM需要占用的内存量

算法:(基于C++)

// 计算邻接矩阵AM需要的内存量
int compute_mem_AM(int v, int e) {
    // 邻接矩阵中v个顶点所占用的字节数 + 所有边中的起始顶点和目标顶点所需的整形长度
    int am = v * v;
    int mem_AM = am * sizeof(bool) + sizeof(int) * 2 * e;
    return mem_AM;
}

解释如下:

该算法同样基于C++,是计算邻接矩阵AM所需占用的内存量。邻接矩阵是使用二维矩阵来存储顶点之间的关系,因此,矩阵中每个元素是一个布尔值(bool),所以矩阵中所有元素的占用空间大小为:

am = v * v

然后,在邻接矩阵中存储所有边,则需要一个长度为2e的数组,因为每条边都有两个顶点。因此,矩阵中保存所有边的起始和目标顶点的数组占用的空间大小为:

sizeof(int) * 2 * e

最终,算法中计算出的内存占用量的公式为:

mem_AM = am * sizeof(bool) + sizeof(int) * 2 * e

  1. 关于问题1和问题2中的算法:

    a. 当n和m相同的时候,邻接矩阵更好,因为邻接矩阵查询两个顶点之间是否有边的操作的复杂度是O(1),而邻接表是O(deg(v)),其中deg(v)是顶点v的度数。当n=m时,图的平均度数为2m/n,因此,使用邻接矩阵的时间复杂度为O(1),而使用邻接表的时间复杂度为O(2m/n)。

    b. 当图G是非常稠密的时候,邻接矩阵更好,因为邻接矩阵可以在O(1)时间内查询两个顶点之间是否有边,而邻接表要在链表中查找,需要O(deg(v))时间。当图G稠密时,每个顶点的度数deg(v)趋近于n,因此,使用邻接矩阵的效率更高。

注:本文所提供的算法基于C++,也适用于其他编程语言。