igraph 参考手册

用于使用 igraph C 库

搜索手册

第 4 章。基本数据类型和接口

1. igraph 数据模型

igraph 库可以处理有向图和无向图。igraph 图是已排序(如果是有向图)或未排序(如果是无向图)标记对的多重集。配对标签加上顶点数始终从零开始,并以边数减一结束。除此之外,每个图还附加一个元数据表,其最重要的条目是图中的顶点数以及该图是有向还是无向。

与边一样,igraph 顶点也用零到顶点数减一之间的数字标记。因此,总而言之,有向图可以想象成这样

  ( vertices: 6,
    directed: yes,
    {
     (0,2),
     (2,2),
     (3,2),
     (3,3),
     (3,4),
     (3,4),
     (4,3),
     (4,1)
    }
  )

这里的边是顶点 ID 的有序对,图是边加上一些元数据的多重集。

无向图是这样的

  ( vertices: 6,
    directed: no,
    {
     (0,2),
     (2,2),
     (2,3),
     (3,3),
     (3,4),
     (3,4),
     (3,4),
     (1,4)
    }
  )

这里,边是两个顶点 ID 的无序对。图是一个边加上元数据的多重集,就像有向图一样。

可以在有向图和无向图之间进行转换,请参阅 igraph_to_directed() igraph_to_undirected() 函数。

igraph 旨在稳健地支持多重图,即在某些顶点对之间具有多条边的图,以及具有自环的图。大多数不支持此类图的函数会检查其输入,如果无效则会发出错误。那些不执行此检查的罕见函数会在其文档中清楚地表明这一点。要从图中删除多条边,可以使用 igraph_simplify()

2. igraph 函数的通用约定

igraph 具有简单且一致的界面。大多数函数会检查其输入的有效性,并在出现问题时显示信息性错误消息。为了支持这一点,大多数函数会返回错误代码。在基本用法中,可以忽略此代码,因为默认行为是在出错时立即中止程序。有关此主题的更多信息,请参阅关于错误处理的部分

结果通常通过输出参数返回,即指向将写入结果的数据结构的指针。在几乎所有情况下,都应预先初始化此数据结构。一些简单的函数直接通过其返回值传达结果 - 这些函数永远不会遇到错误。

3. 原子数据类型

igraph 引入了标准 C 数据类型的几个别名,然后在整个库中使用。这些类型中最重要的是 igraph_integer_t,它是 32 位或 64 位有符号整数的别名,具体取决于 igraph 是在 32 位模式还是 64 位模式下编译的。igraph_integer_t 的大小也会影响 igraph 图可以表示的最大顶点数,因为顶点数存储在 igraph_integer_t 类型的变量中。

由于 igraph_integer_t 类型的变量的大小可能会根据 igraph 的编译方式而变化,因此您不能简单地使用 %d%ld 作为 printf 格式字符串中 igraph 整数的占位符。igraph 提供了 IGRAPH_PRId 宏,该宏根据 igraph_integer_t 的大小映射到 dldlld,并且您必须在 printf 格式字符串中使用此宏以避免编译器警告。

igraph_integer_t 如何映射到库中的标准大小有符号整数类似,igraph_uint_t 映射到 32 位或 64 位无符号整数。保证 igraph_integer_t 的大小与 igraph_uint_t 的大小相同。igraph 提供了 IGRAPH_PRIu 作为 igraph_uint_t 类型变量的格式字符串占位符。

实数(即可能为分数或无穷大的数量)用名为 igraph_real_t 的类型表示。目前 igraph_real_t 始终是 double 的别名,但为了保持一致性,在您自己的代码中使用 igraph_real_t 仍然是一个好习惯。

布尔值用名为 igraph_bool_t 的类型表示。它试图尽可能小,因为它只需要表示一个真值。为了打印的目的,您可以将其视为一个整数,并在格式字符串中使用 %d 作为 igraph_bool_t 的占位符。

igraph_integer_tigraph_uint_t 的上限和下限由名为 IGRAPH_INTEGER_MINIGRAPH_INTEGER_MAXIGRAPH_UINT_MINIGRAPH_UINT_MAX 的常量提供。

4. 基本接口

这是 igraph 中的最基本 API。所有其他函数都使用此最小集来创建和操作图。

这是一个非常重要的原则,因为它使得仅通过实现此最小集就可以实现其他数据表示。

本节列出了从 igraph 用户的角度来看,被认为是核心 API 的一部分的所有函数和宏。其中一些函数和宏具有明智的默认实现,这些实现只是调用其他一些核心函数(例如,igraph_empty() 调用 igraph_empty_attrs(),并带有 null 属性表指针)。如果您希望尝试实现替代数据类型,则您需要替换的实际函数数量较少,因为在大多数情况下您可以依赖相同的默认实现。

4.1. 图构造函数和析构函数

4.1.1. igraph_empty — 创建一个具有一些顶点且没有边的空图。

igraph_error_t igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed);

最基本的构造函数,所有其他构造函数都应该调用它来创建一个最小的图对象。我们在上述描述中使用术语“空图”应与空图或零图的数学定义区分开来。严格来说,图论中的空图或零图是没有顶点和边的图。但是,通过 igraph 中使用的“空图”,我们指的是具有零个或多个顶点但没有边的图。

参数: 

:

指向尚未初始化的图对象的指针。

n:

图中的顶点数,预计为一个非负整数。

有向:

布尔值;该图是否是有向的。支持的值为

IGRAPH_DIRECTED

该图将是有向的。

IGRAPH_UNDIRECTED

该图将是无向的。

返回值: 

错误代码:IGRAPH_EINVAL:无效的顶点数。

时间复杂度:对于具有 |V| 个顶点(且没有边)的图,为 O(|V|)。

示例 4.1. 文件 examples/simple/creation.c

#include <igraph.h>
#include <assert.h>

int main(void) {
    igraph_t graph;
    igraph_vector_int_t edges;

    /* Create a directed graph with no vertices or edges. */
    igraph_empty(&graph, 0, IGRAPH_DIRECTED);

    /* Add 5 vertices. Vertex IDs will range from 0 to 4, inclusive. */
    igraph_add_vertices(&graph, 5, NULL);

    /* Add 5 edges, specified as 5 consecutive pairs of vertex IDs
     * stored in an integer vector. */
    igraph_vector_int_init_int(&edges, 10,
                               0,1, 0,2, 3,1, 2,1, 0,4);
    igraph_add_edges(&graph, &edges, NULL);

    igraph_vector_int_destroy(&edges);

    /* Now the graph has 5 vertices and 5 edges. */
    assert(igraph_vcount(&graph) == 5);
    assert(igraph_ecount(&graph) == 5);

    igraph_destroy(&graph);

    return 0;
}


4.1.2. igraph_empty_attrs — 创建一个具有一些顶点、没有边和一些图属性的空图。

igraph_error_t igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void *attr);

如果您希望在初始化后立即添加一些图属性,请使用此函数而不是 igraph_empty()。此函数目前对普通用户来说不是很有趣。只需在此处提供 0 或使用 igraph_empty()

此函数不设置任何顶点属性。要创建一个具有顶点属性的图,请调用此函数并指定 0 个顶点,然后使用 igraph_add_vertices() 添加顶点及其属性。

参数: 

:

指向尚未初始化的图对象的指针。

n:

图中的顶点数;预计为一个非负整数。

有向:

布尔值;该图是否是有向的。支持的值为

IGRAPH_DIRECTED

创建一个有向图。

IGRAPH_UNDIRECTED

创建一个无向图。

attr:

图属性。如果不设置图属性,请提供 NULL

返回值: 

错误代码:IGRAPH_EINVAL:无效的顶点数。

另请参阅: 

igraph_empty() 创建一个没有属性的空图;igraph_add_vertices()igraph_add_edges() 添加顶点和边,可能带有关联的属性。

时间复杂度:对于具有 |V| 个顶点(且没有边)的图,为 O(|V|)。

4.1.3. igraph_copy — 创建一个图的精确(深度)副本。

igraph_error_t igraph_copy(igraph_t *to, const igraph_t *from);

此函数深度复制一个图对象以创建其精确副本。创建新副本后,不再需要时应通过调用 igraph_destroy() 来销毁它。

您还可以通过简单地使用标准赋值运算符来创建图的浅层副本,但请小心不要销毁浅层副本。为避免此错误,不建议创建浅层副本。

参数: 

:

指向未初始化的图对象的指针。

:

指向要复制的图对象的指针。

返回值: 

错误代码。

时间复杂度:对于具有 |V| 个顶点和 |E| 条边的图,为 O(|V|+|E|)。

示例 4.2. 文件 examples/simple/igraph_copy.c

#include <igraph.h>

int main(void) {

    igraph_t g1, g2;
    igraph_vector_int_t v1, v2;

    igraph_vector_int_init(&v1, 8);
    VECTOR(v1)[0] = 0;
    VECTOR(v1)[1] = 1;
    VECTOR(v1)[2] = 1;
    VECTOR(v1)[3] = 2;
    VECTOR(v1)[4] = 2;
    VECTOR(v1)[5] = 3;
    VECTOR(v1)[6] = 2;
    VECTOR(v1)[7] = 2;

    igraph_create(&g1, &v1, 0, 0);
    igraph_copy(&g2, &g1);

    igraph_vector_int_init(&v2, 0);
    igraph_get_edgelist(&g2, &v2, 0);
    if (!igraph_vector_int_all_e(&v1, &v2)) {
        return 1;
    }

    igraph_vector_int_destroy(&v1);
    igraph_vector_int_destroy(&v2);
    igraph_destroy(&g1);
    igraph_destroy(&g2);

    return 0;
}


4.1.4. igraph_destroy — 释放为图对象分配的内存。

void igraph_destroy(igraph_t *graph);

应该为每个图对象完全调用一次此函数。

此函数使所有迭代器失效(当然),但无论如何,应该在图本身之前销毁图的迭代器。

参数: 

:

指向要释放的图。

时间复杂度:操作系统特定。

4.2. 基本查询操作

4.2.1. igraph_vcount — 图中的顶点数。

igraph_integer_t igraph_vcount(const igraph_t *graph);

参数: 

:

图。

返回值: 

顶点数。

时间复杂度:O(1)

4.2.2. igraph_ecount — 图中的边数。

igraph_integer_t igraph_ecount(const igraph_t *graph);

参数: 

:

图。

返回值: 

边数。

时间复杂度:O(1)

4.2.3. igraph_is_directed — 这是有向图吗?

igraph_bool_t igraph_is_directed(const igraph_t *graph);

参数: 

:

图。

返回值: 

布尔值,如果图是有向图,则为 true,否则为 false

时间复杂度:O(1)

示例 4.3. 文件 examples/simple/igraph_is_directed.c

#include <igraph.h>

int main(void) {

    igraph_t g;

    igraph_empty(&g, 0, 0);
    if (igraph_is_directed(&g)) {
        return 1;
    }
    igraph_destroy(&g);

    igraph_empty(&g, 0, 1);
    if (!igraph_is_directed(&g)) {
        return 2;
    }
    igraph_destroy(&g);

    return 0;
}


4.2.4. igraph_edge — 返回边的头部和尾部顶点。

igraph_error_t igraph_edge(
    const igraph_t *graph, igraph_integer_t eid,
    igraph_integer_t *from, igraph_integer_t *to
);

参数: 

:

图对象。

eid:

边 ID。

:

指向 igraph_integer_t 的指针。边的尾部(源)将放在此处。

:

指向 igraph_integer_t 的指针。边的头部(目标)将放在此处。

返回值: 

错误代码。

另请参阅: 

igraph_get_eid() 用于相反的操作;igraph_edges() 获取多条边的端点;IGRAPH_TO()IGRAPH_FROM()IGRAPH_OTHER() 用于更快但未进行错误检查的版本。

在 0.2 版本中添加。

时间复杂度:O(1)。

4.2.5. igraph_edges — 给出边序列的头部和尾部顶点。

igraph_error_t igraph_edges(const igraph_t *graph, igraph_es_t eids, igraph_vector_int_t *edges);

参数: 

:

图对象。

eids:

边选择器,边的序列。

:

指向初始化的向量的指针。每条边的起始和结束点将放在此处。

返回值: 

错误代码。

另请参阅: 

igraph_get_edgelist() 获取所有边的端点;igraph_get_eids() 用于相反的操作;igraph_edge() 用于获取单个边的端点;IGRAPH_TO()IGRAPH_FROM()IGRAPH_OTHER() 用于更快但未进行错误检查的方法。

时间复杂度:O(k),其中 k 是选择器中的边数。

4.2.6. IGRAPH_FROM — 边的源顶点。

#define IGRAPH_FROM(graph,eid)

igraph_edge() 更快,但不会进行错误检查:假定 eid 有效。

参数: 

:

图。

eid:

边 ID。

返回值: 

边的源顶点。

另请参阅: 

如果需要错误检查,请使用 igraph_edge()

4.2.7. IGRAPH_TO — 边的目标顶点。

#define IGRAPH_TO(graph,eid)

igraph_edge() 更快,但不会进行错误检查:假定 eid 有效。

参数: 

:

图对象。

eid:

边 ID。

返回值: 

边的目标顶点。

另请参阅: 

如果需要错误检查,请使用 igraph_edge()

4.2.8. IGRAPH_OTHER — 边的另一个端点。

#define IGRAPH_OTHER(graph,eid,vid)

通常与无向边一起使用,当边的某个端点已知且需要另一个端点时。不会进行错误检查:假定 eidvid 有效。

参数: 

:

图对象。

eid:

边 ID。

vid:

边的一个端点的顶点 ID。

返回值: 

边的另一个端点。

另请参阅: 

使用 IGRAPH_TO()IGRAPH_FROM() 获取有向边的源和目标。

4.2.9. igraph_get_eid — 从边的端点获取边 ID。

igraph_error_t igraph_get_eid(const igraph_t *graph, igraph_integer_t *eid,
                   igraph_integer_t from, igraph_integer_t to,
                   igraph_bool_t directed, igraph_bool_t error);

对于无向图,fromto 是可交换的。

参数: 

:

图对象。

eid:

指向整数的指针,边 ID 将存储在此处。如果 error 为 false 并且未找到边,则将返回 -1

:

边的起点。

:

边的终点。

有向:

布尔值,是否在有向图中搜索有向边。对于无向图,此值将被忽略。

错误:

布尔值,如果未找到边是否报告错误。如果为 false,则将 -1 分配给 eid。请注意,输入参数(fromto)中的无效顶点 ID 始终会触发错误,而不管此设置如何。

返回值: 

错误代码。

另请参阅: 

igraph_edge() 用于相反的操作,igraph_get_all_eids_between() 用于检索一对顶点之间的所有边 ID。

时间复杂度:O(log (d)),其中 d 是 from 的出度和 to 的入度中较小的值,如果 directed 为 true。如果 directed 为 false,则为 O(log(d)+log(d2)),其中 d 与之前相同,d2 是 to 的出度和 from 的入度中的最小值。

示例 4.4. 文件 examples/simple/igraph_get_eid.c

#include <igraph.h>

int main(void) {
    igraph_t g;
    igraph_integer_t eid;
    igraph_vector_int_t hist;
    igraph_integer_t i;

    /* DIRECTED */

    igraph_star(&g, 10, IGRAPH_STAR_OUT, 0);

    igraph_vector_int_init(&hist, 9);

    for (i = 1; i < 10; i++) {
        igraph_get_eid(&g, &eid, 0, i, IGRAPH_DIRECTED, /*error=*/ true);
        VECTOR(hist)[ eid ] = 1;
    }

    igraph_vector_int_print(&hist);

    igraph_vector_int_destroy(&hist);
    igraph_destroy(&g);

    /* UNDIRECTED */

    igraph_star(&g, 10, IGRAPH_STAR_UNDIRECTED, 0);

    igraph_vector_int_init(&hist, 9);

    for (i = 1; i < 10; i++) {
        igraph_get_eid(&g, &eid, 0, i, IGRAPH_UNDIRECTED, /*error=*/ true);
        VECTOR(hist)[ eid ] += 1;
        igraph_get_eid(&g, &eid, i, 0, IGRAPH_DIRECTED, /*error=*/ true);
        VECTOR(hist)[ eid ] += 1;
    }
    igraph_vector_int_print(&hist);

    igraph_vector_int_destroy(&hist);
    igraph_destroy(&g);

    return 0;
}


在 0.2 版本中添加。

4.2.10. igraph_get_eids — 根据相邻顶点返回边 ID。

igraph_error_t igraph_get_eids(const igraph_t *graph, igraph_vector_int_t *eids,
                    const igraph_vector_int_t *pairs,
                    igraph_bool_t directed, igraph_bool_t error);

用于查找边的顶点 ID 对是从 pairs 向量中连续获取的,即 VECTOR(pairs)[0]VECTOR(pairs)[1] 指定第一对,VECTOR(pairs)[2]VECTOR(pairs)[3] 指定第二对,依此类推。

如果您有一系列描述图上路径的顶点 ID,请使用 igraph_expand_path_to_pairs() 将其转换为沿路径的顶点对列表。

如果 error 参数为 true,则指定未连接的顶点对是一个错误。否则,对于顶点对之间至少没有一条边的情况,将报告 -1。

如果图中有多条边,则这些边将被忽略;也就是说,对于给定的顶点 ID 对,即使该对在 pairs 中多次出现,igraph 始终返回相同的边 ID。

参数: 

:

输入图。

eids:

指向初始化的向量的指针,结果存储在此处。它将根据需要调整大小。

:

向量,给出要获取边的顶点对。

有向:

布尔值,是否考虑有向图中的边方向。对于无向图,此值将被忽略。

错误:

布尔值,提供非连接顶点是否为错误。如果为 false,则为非连接对返回 -1。

返回值: 

错误代码。

时间复杂度:O(n log(d)),其中 n 是查询的边数,d 是顶点的平均度。

另请参阅: 

igraph_get_eid() 用于单条边。

示例 4.5. 文件 examples/simple/igraph_get_eids.c

#include <igraph.h>
#include <stdlib.h>

void print_vector_int(igraph_vector_int_t *v, FILE *f) {
    igraph_integer_t i;
    for (i = 0; i < igraph_vector_int_size(v); i++) {
        fprintf(f, " %" IGRAPH_PRId, VECTOR(*v)[i]);
    }
    fprintf(f, "\n");
}

int main(void) {
    igraph_t g;
    igraph_integer_t nodes = 100;
    igraph_integer_t edges = 1000;
    igraph_real_t p = 3.0 / nodes;
    igraph_integer_t runs = 10;
    igraph_integer_t r, e, ecount;
    igraph_vector_int_t eids, pairs, path;

    igraph_rng_seed(igraph_rng_default(), 42); /* make tests deterministic */

    igraph_vector_int_init(&pairs, edges * 2);
    igraph_vector_int_init(&path, 0);
    igraph_vector_int_init(&eids, 0);

    for (r = 0; r < runs; r++) {
        igraph_vector_int_resize(&pairs, edges * 2);
        igraph_vector_int_clear(&path);
        igraph_vector_int_clear(&eids);

        igraph_erdos_renyi_game_gnp(&g, nodes, p, /*directed=*/ 0, /*loops=*/ 0);
        ecount = igraph_ecount(&g);
        for (e = 0; e < edges; e++) {
            igraph_integer_t edge = RNG_INTEGER(0, ecount - 1);
            VECTOR(pairs)[2 * e] = IGRAPH_FROM(&g, edge);
            VECTOR(pairs)[2 * e + 1] = IGRAPH_TO(&g, edge);
        }
        igraph_get_eids(&g, &eids, &pairs, /* directed= */ 0, /*error=*/ 1);
        for (e = 0; e < edges; e++) {
            igraph_integer_t edge = VECTOR(eids)[e];
            igraph_integer_t from1 = VECTOR(pairs)[2 * e];
            igraph_integer_t to1 = VECTOR(pairs)[2 * e + 1];
            igraph_integer_t from2 = IGRAPH_FROM(&g, edge);
            igraph_integer_t to2 = IGRAPH_TO(&g, edge);
            igraph_integer_t min1 = from1 < to1 ? from1 : to1;
            igraph_integer_t max1 = from1 < to1 ? to1 : from1;
            igraph_integer_t min2 = from2 < to2 ? from2 : to2;
            igraph_integer_t max2 = from2 < to2 ? to2 : from2;
            if (min1 != min2 || max1 != max2) {
                return 11;
            }
        }

        igraph_diameter(&g, /*res=*/ 0, /*from=*/ 0, /*to=*/ 0, &path, NULL,
                        IGRAPH_UNDIRECTED, /*unconn=*/ 1);
        igraph_vector_int_update(&pairs, &path);
        igraph_expand_path_to_pairs(&pairs);
        igraph_get_eids(&g, &eids, &pairs, 0, /*error=*/ 1);
        for (e = 0; e < igraph_vector_int_size(&path) - 1; e++) {
            igraph_integer_t edge = VECTOR(eids)[e];
            igraph_integer_t from1 = VECTOR(path)[e];
            igraph_integer_t to1 = VECTOR(path)[e + 1];
            igraph_integer_t from2 = IGRAPH_FROM(&g, edge);
            igraph_integer_t to2 = IGRAPH_TO(&g, edge);
            igraph_integer_t min1 = from1 < to1 ? from1 : to1;
            igraph_integer_t max1 = from1 < to1 ? to1 : from1;
            igraph_integer_t min2 = from2 < to2 ? from2 : to2;
            igraph_integer_t max2 = from2 < to2 ? to2 : from2;
            if (min1 != min2 || max1 != max2) {
                return 12;
            }
        }

        igraph_destroy(&g);
    }

    igraph_vector_int_destroy(&path);
    igraph_vector_int_destroy(&pairs);
    igraph_vector_int_destroy(&eids);

    return 0;
}


4.2.11. igraph_get_all_eids_between — 返回一对顶点之间的所有边 ID。

igraph_error_t igraph_get_all_eids_between(
    const igraph_t *graph, igraph_vector_int_t *eids,
    igraph_integer_t source, igraph_integer_t target, igraph_bool_t directed
);

对于无向图,sourcetarget 是可交换的。

参数: 

:

输入图。

eids:

指向初始化的向量的指针,结果存储在此处。它将根据需要调整大小。

来源:

源顶点的 ID

目标:

目标顶点的 ID

有向:

布尔值,是否考虑有向图中的边方向。对于无向图,此值将被忽略。

返回值: 

错误代码。

时间复杂度:TODO

另请参阅: 

igraph_get_eid() 用于单条边。

4.2.12. igraph_neighbors — 顶点的相邻顶点。

igraph_error_t igraph_neighbors(const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t pnode,
        igraph_neimode_t mode);

参数: 

:

要操作的图。

neis:

此向量将包含结果。应预先初始化该向量,并且将调整其大小。从 igraph 0.4 版本开始,此向量始终排序,顶点 ID 按升序排列。如果一个相邻顶点通过多条边连接,则该相邻顶点将被多次返回。

pnode:

要搜索相邻顶点的节点的 ID。

模式:

定义在有向图中搜索相邻顶点的方式。它可以具有以下值:IGRAPH_OUT,搜索可从指定顶点通过边到达的顶点;IGRAPH_IN,搜索指定顶点可从其到达的顶点;IGRAPH_ALL,搜索两种顶点。对于无向图,此参数将被忽略。

返回值: 

错误代码:IGRAPH_EINVVID:无效的顶点 ID。IGRAPH_EINVMODE:无效的模式参数。IGRAPH_ENOMEM:内存不足。

时间复杂度:O(d),d 是查询顶点的相邻顶点数。

示例 4.6. 文件 examples/simple/igraph_neighbors.c

#include <igraph.h>

int main(void) {

    igraph_t g;
    igraph_vector_int_t v;

    igraph_vector_int_init(&v, 0);
    igraph_small(&g, 4, IGRAPH_DIRECTED, 0,1, 1,2, 2,3, 2,2, -1);

    igraph_neighbors(&g, &v, 2, IGRAPH_OUT);
    igraph_vector_int_sort(&v);
    igraph_vector_int_print(&v);

    igraph_neighbors(&g, &v, 2, IGRAPH_IN);
    igraph_vector_int_sort(&v);
    igraph_vector_int_print(&v);

    igraph_neighbors(&g, &v, 2, IGRAPH_ALL);
    igraph_vector_int_sort(&v);
    igraph_vector_int_print(&v);

    igraph_vector_int_destroy(&v);
    igraph_destroy(&g);
    return 0;
}


4.2.13. igraph_incident — 给出顶点的关联边。

igraph_error_t igraph_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t pnode,
        igraph_neimode_t mode);

参数: 

:

图对象。

eids:

初始化的向量。将调整其大小以容纳结果。

pnode:

顶点 ID。

模式:

指定对于有向图包括哪些类型的边。IGRAPH_OUT 表示仅传出边,IGRAPH_IN 表示仅传入边,IGRAPH_ALL 表示两者。对于无向图,此参数将被忽略。

返回值: 

错误代码。IGRAPH_EINVVID:无效的 pnode 参数,IGRAPH_EINVMODE:无效的 mode 参数。

在 0.2 版本中添加。

时间复杂度:O(d),到 pnode 的关联边数。

4.2.14. igraph_degree — 图中某些顶点的度。

igraph_error_t igraph_degree(const igraph_t *graph, igraph_vector_int_t *res,
                  const igraph_vs_t vids,
                  igraph_neimode_t mode, igraph_bool_t loops);

此函数计算指定顶点的入度、出度或总度。

此函数将结果作为 igraph_integer_t 值的向量返回。在使用 igraph_real_t 的应用程序中,请使用带有 NULL 权重的 igraph_strength()

参数: 

:

图。

res:

整数向量,将包含结果。应初始化它,并且将调整其大小以适合。

vids:

顶点选择器,给出要计算度的顶点 ID。

模式:

定义有向图的度的类型。有效模式为:IGRAPH_OUT,出度;IGRAPH_IN,入度;IGRAPH_ALL,总度(入度和出度之和)。对于无向图,此参数将被忽略。

循环:

布尔值,给出是否应计算自循环。

返回值: 

错误代码:IGRAPH_EINVVID:无效的顶点 ID。IGRAPH_EINVMODE:无效的模式参数。

时间复杂度:如果 loopstrue,则为 O(v),否则为 O(v*d)。v 是要计算度的顶点数,d 是它们的(平均)度。

另请参阅: 

igraph_strength() 用于考虑边权重的版本;igraph_degree_1() 用于有效地计算单个顶点的度;如果您只需要最大度,请使用 igraph_maxdegree()

示例 4.7. 文件 examples/simple/igraph_degree.c

#include <igraph.h>

igraph_bool_t handshaking_lemma(igraph_t *g, igraph_vector_int_t *v) {
    /* Consistency check of the handshaking lemma:
     * If d is the sum of all vertex degrees, then d = 2|E|. */
    return igraph_vector_int_sum(v) == 2 * igraph_ecount(g);
}

int main(void) {

    igraph_t g;
    igraph_vector_int_t v;
    igraph_vector_int_t seq;
    igraph_integer_t mdeg;

    /* Create graph */
    igraph_vector_int_init(&v, 8);
    igraph_small(&g, 4, IGRAPH_DIRECTED, 0,1, 1,2, 2,3, 2,2, -1);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    if (!handshaking_lemma(&g, &v)) {
        exit(3);
    }

    igraph_destroy(&g);

    igraph_small(&g, 4, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,3, 2,2, -1);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS);
    igraph_vector_int_print(&v);

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    if (!handshaking_lemma(&g, &v)) {
        exit(4);
    }

    /* Degree of the same vertex multiple times */

    igraph_vector_int_init(&seq, 3);
    VECTOR(seq)[0] = 2;
    VECTOR(seq)[1] = 0;
    VECTOR(seq)[2] = 2;
    igraph_degree(&g, &v, igraph_vss_vector(&seq), IGRAPH_ALL, IGRAPH_LOOPS);
    igraph_vector_int_print(&v);

    igraph_destroy(&g);
    igraph_vector_int_destroy(&seq);

    /* Maximum degree */

    igraph_ring(&g, 10, IGRAPH_UNDIRECTED, /* mutual */ false, /* circular */ false);
    igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (mdeg != 2) {
        exit(5);
    }

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (! handshaking_lemma(&g, &v)) {
        exit(6);
    }
    igraph_destroy(&g);

    igraph_full(&g, 10, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);
    igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (mdeg != 9) {
        exit(7);
    }

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (! handshaking_lemma(&g, &v)) {
        exit(8);
    }
    igraph_destroy(&g);

    igraph_star(&g, 10, IGRAPH_STAR_OUT, /* center */ 0);
    igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_OUT, IGRAPH_LOOPS);
    if (mdeg != 9) {
        exit(9);
    }
    igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_IN, IGRAPH_LOOPS);
    if (mdeg != 1) {
        exit(10);
    }
    igraph_maxdegree(&g, &mdeg, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (mdeg != 9) {
        exit(11);
    }

    igraph_degree(&g, &v, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
    if (! handshaking_lemma(&g, &v)) {
        exit(12);
    }
    igraph_destroy(&g);

    igraph_vector_int_destroy(&v);

    return 0;
}


4.2.15. igraph_degree_1 — 图中单个顶点的度。

igraph_error_t igraph_degree_1(const igraph_t *graph, igraph_integer_t *deg,
                               igraph_integer_t vid, igraph_neimode_t mode, igraph_bool_t loops);

此函数计算单个顶点的入度、出度或总度。对于单个顶点,调用 igraph_degree() 比调用此函数更有效。

参数: 

:

图。

deg:

指向将存储计算度的整数的指针。

vid:

将计算度的顶点。

模式:

定义有向图的度的类型。有效模式为:IGRAPH_OUT,出度;IGRAPH_IN,入度;IGRAPH_ALL,总度(入度和出度之和)。对于无向图,此参数将被忽略。

循环:

布尔值,给出是否应计算自循环。

返回值: 

错误代码。

另请参阅: 

igraph_degree() 用于一次计算多个顶点的度。

时间复杂度:如果 loopstrue,则为 O(1),否则为 O(d),其中 d 是度。

4.3. 添加和删除顶点和边

4.3.1. igraph_add_edge — 向图中添加一条边。

igraph_error_t igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to);

对于有向图,边从 from 指向 to

请注意,如果要向一个大图添加多条边,则一条一条地添加效率低下,最好将它们收集到一个向量中,并通过单个 igraph_add_edges() 调用添加所有边。

参数: 

igraph:

图。

:

边的第一个顶点的 ID。

:

边的第二个顶点的 ID。

返回值: 

错误代码。

另请参阅: 

igraph_add_edges() 用于添加多条边,igraph_delete_edges() 用于删除边,igraph_add_vertices() 用于添加顶点。

时间复杂度:O(|V|+|E|),边数加上顶点数。

4.3.2. igraph_add_edges — 向图对象添加边。

igraph_error_t igraph_add_edges(igraph_t *graph, const igraph_vector_int_t *edges,
                     void *attr);

这些边在向量中给出,前两个元素定义第一条边(对于有向图,顺序为 fromto)。该向量应包含偶数个整数,介于零和图中的顶点数减一之间(包括端点)。如果您还想添加新顶点,请先调用 igraph_add_vertices()

参数: 

:

将添加边的图。

:

边本身。

attr:

新边的属性。如果不需要边属性,则可以在此处提供空指针。

返回值: 

错误代码:IGRAPH_EINVEVECTOR:无效的(奇数)边向量长度,IGRAPH_EINVVID:边向量中无效的顶点 ID。

此函数使所有迭代器失效。

时间复杂度:O(|V|+|E|),其中 |V| 是扩展图中的顶点数,|E| 是边数。

示例 4.8. 文件 examples/simple/creation.c

#include <igraph.h>
#include <assert.h>

int main(void) {
    igraph_t graph;
    igraph_vector_int_t edges;

    /* Create a directed graph with no vertices or edges. */
    igraph_empty(&graph, 0, IGRAPH_DIRECTED);

    /* Add 5 vertices. Vertex IDs will range from 0 to 4, inclusive. */
    igraph_add_vertices(&graph, 5, NULL);

    /* Add 5 edges, specified as 5 consecutive pairs of vertex IDs
     * stored in an integer vector. */
    igraph_vector_int_init_int(&edges, 10,
                               0,1, 0,2, 3,1, 2,1, 0,4);
    igraph_add_edges(&graph, &edges, NULL);

    igraph_vector_int_destroy(&edges);

    /* Now the graph has 5 vertices and 5 edges. */
    assert(igraph_vcount(&graph) == 5);
    assert(igraph_ecount(&graph) == 5);

    igraph_destroy(&graph);

    return 0;
}


4.3.3. igraph_add_vertices — 向图中添加顶点。

igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr);

此函数使所有迭代器失效。

参数: 

:

要扩展的图对象。

nv:

指定要添加的顶点数的非负整数。

attr:

新顶点的属性。如果不需要顶点属性,则可以在此处提供空指针。

返回值: 

错误代码:IGRAPH_EINVAL:无效的新顶点数。

时间复杂度:O(|V|),其中 |V| 是扩展图中的顶点数。

示例 4.9. 文件 examples/simple/creation.c

#include <igraph.h>
#include <assert.h>

int main(void) {
    igraph_t graph;
    igraph_vector_int_t edges;

    /* Create a directed graph with no vertices or edges. */
    igraph_empty(&graph, 0, IGRAPH_DIRECTED);

    /* Add 5 vertices. Vertex IDs will range from 0 to 4, inclusive. */
    igraph_add_vertices(&graph, 5, NULL);

    /* Add 5 edges, specified as 5 consecutive pairs of vertex IDs
     * stored in an integer vector. */
    igraph_vector_int_init_int(&edges, 10,
                               0,1, 0,2, 3,1, 2,1, 0,4);
    igraph_add_edges(&graph, &edges, NULL);

    igraph_vector_int_destroy(&edges);

    /* Now the graph has 5 vertices and 5 edges. */
    assert(igraph_vcount(&graph) == 5);
    assert(igraph_ecount(&graph) == 5);

    igraph_destroy(&graph);

    return 0;
}


4.3.4. igraph_delete_edges — 从图中删除边。

igraph_error_t igraph_delete_edges(igraph_t *graph, igraph_es_t edges);

要删除的边指定为边选择器。

此函数无法删除顶点;即使顶点失去所有边,也会被保留。

此函数使所有迭代器失效。

参数: 

:

要操作的图。

:

要删除的边。

返回值: 

错误代码。

时间复杂度:O(|V|+|E|),其中 |V| 和 |E| 分别是原始图中的顶点和边的数量。

示例 4.10.  文件 examples/simple/igraph_delete_edges.c

#include <igraph.h>

int main(void) {

    igraph_t g;
    igraph_es_t es;

    igraph_small(&g, 4, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,2, 2,3, -1);

    igraph_es_pairs_small(&es, IGRAPH_DIRECTED, 3, 2, -1);
    igraph_delete_edges(&g, es);
    if (igraph_ecount(&g) != 3) {
        return 1;
    }

    igraph_es_destroy(&es);
    igraph_destroy(&g);

    return 0;
}


4.3.5. igraph_delete_vertices — 从图中移除一些顶点(以及它们的所有边)。

igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices);

此函数会更改顶点的 ID(除非在某些非常特殊的情况下,但无论如何都不应依赖这些情况)。

此函数使所有迭代器失效。

参数: 

:

要操作的图。

vertices:

要删除的顶点的 ID,以向量形式表示。该向量可能多次包含相同的 ID。

返回值: 

错误代码:IGRAPH_EINVVID:无效的顶点 ID。

时间复杂度:O(|V|+|E|),|V| 和 |E| 是原始图中顶点和边的数量。

示例 4.11.  文件 examples/simple/igraph_delete_vertices.c

#include <igraph.h>

int main(void) {
    igraph_t g;

    /* without edges */
    igraph_small(&g, 15, IGRAPH_UNDIRECTED, -1);

    igraph_delete_vertices(&g, igraph_vss_1(2));
    if (igraph_vcount(&g) != 14)  {
        return 2;
    }
    igraph_destroy(&g);

    /* with edges */
    igraph_small(&g, 4, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,3, 2,2, -1);
    igraph_delete_vertices(&g, igraph_vss_1(2));
    if (igraph_vcount(&g) != 3) {
        return 3;
    }
    if (igraph_ecount(&g) != 1) {
        return 4;
    }

    igraph_destroy(&g);

    return 0;
}


4.3.6. igraph_delete_vertices_idx — 从图中移除一些顶点(以及它们的所有边)。

igraph_error_t igraph_delete_vertices_idx(
    igraph_t *graph, const igraph_vs_t vertices, igraph_vector_int_t *idx,
    igraph_vector_int_t *invidx
);

此函数会更改顶点的 ID(除非在某些非常特殊的情况下,但无论如何都不应依赖这些情况)。您可以使用 idx 参数获取从旧顶点 ID 到新顶点 ID 的映射,并使用 newidx 参数获取反向映射。

此函数使所有迭代器失效。

参数: 

:

要操作的图。

vertices:

要删除的顶点的 ID,以向量形式表示。该向量可能多次包含相同的 ID。

idx:

一个可选的向量指针,提供从删除之前的顶点 ID 到删除之后的顶点 ID 的映射,再加 1。零用于表示在操作期间删除的顶点。如果您不感兴趣,可以在此处提供 NULL

invidx:

一个可选的向量指针,提供从删除之后的顶点 ID 到删除之前的顶点 ID 的映射。如果您不感兴趣,可以在此处提供 NULL

返回值: 

错误代码:IGRAPH_EINVVID:无效的顶点 ID。

时间复杂度:O(|V|+|E|),|V| 和 |E| 是原始图中顶点和边的数量。

示例 4.12.  文件 examples/simple/igraph_delete_vertices.c

#include <igraph.h>

int main(void) {
    igraph_t g;

    /* without edges */
    igraph_small(&g, 15, IGRAPH_UNDIRECTED, -1);

    igraph_delete_vertices(&g, igraph_vss_1(2));
    if (igraph_vcount(&g) != 14)  {
        return 2;
    }
    igraph_destroy(&g);

    /* with edges */
    igraph_small(&g, 4, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,3, 2,2, -1);
    igraph_delete_vertices(&g, igraph_vss_1(2));
    if (igraph_vcount(&g) != 3) {
        return 3;
    }
    if (igraph_ecount(&g) != 1) {
        return 4;
    }

    igraph_destroy(&g);

    return 0;
}


5. 杂项宏和辅助函数

5.1. IGRAPH_VCOUNT_MAX — igraph 图中支持的最大顶点数。

#define IGRAPH_VCOUNT_MAX 

此常量的值比 IGRAPH_INTEGER_MAX 小 1。当 igraph 以 32 位模式编译时,这意味着您最多只能有 231 – 2(大约 21 亿)个顶点。在 64 位模式下,限制为 263 – 2,因此您更有可能由于其他原因而遇到内存不足的问题,然后再达到此限制。

5.2. IGRAPH_ECOUNT_MAX — igraph 图中支持的最大边数。

#define IGRAPH_ECOUNT_MAX 

此常量的值是 IGRAPH_INTEGER_MAX 的一半。当 igraph 以 32 位模式编译时,这意味着您最多只能有大约 230(大约 10.7 亿)个顶点。在 64 位模式下,限制约为 262,因此您更有可能由于其他原因而遇到内存不足的问题,然后再达到此限制。

5.3. igraph_expand_path_to_pairs — 辅助函数,用于将描述路径的顶点 ID 序列转换为“pairs”向量。

igraph_error_t igraph_expand_path_to_pairs(igraph_vector_int_t* path);

当您在图中有一个顶点 ID 序列,并且想要检索它们之间边的 ID 时,此函数很有用。该函数会复制向量中除第一个和最后一个元素之外的所有元素,从而有效地将路径转换为可以传递给 igraph_get_eids() 的顶点 ID 向量。

参数: 

path:

输入向量。它将在原地修改,并且会根据需要调整大小。当向量包含少于两个顶点 ID 时,它将被清除。

返回值: 

错误代码:如果没有足够的内存来扩展向量,则为 IGRAPH_ENOMEM

5.4. igraph_invalidate_cache — 使 igraph 图的内部缓存无效。

void igraph_invalidate_cache(const igraph_t* graph);

igraph 图在其内部数据结构中缓存关于自身的一些基本属性。此函数会使缓存的内容无效,并强制在下次需要时重新计算缓存的属性。

在正常使用期间,您不需要调用此函数;但是,如果我们怀疑您在 igraph 的缓存处理中遇到了错误,我们可能会要求您显式调用此函数。无效缓存条目的一个明显的迹象是,缓存的 igraph 函数(例如 igraph_is_dag()igraph_is_simple())的结果在缓存失效前后不同。

参数: 

:

要使其缓存失效的图。

时间复杂度:O(1)。

5.5. igraph_is_same_graph — 两个图是否是相同的标记图?

igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *res);

如果两个图具有相同的顶点和边集,则认为它们是相同的。相同的图在 igraph 中可能具有多个不同的表示形式,因此需要此函数。

此函数验证两个图是否具有相同的方向性,相同的顶点数,并且当以顶点索引的形式写入时,它们是否包含完全相同的边(无论其顺序如何)。不考虑图属性。

此概念与同构不同。例如,图 0-1, 2-11-2, 0-1 被认为是相同的,因为它们仅在它们的边列表的顺序和无向边中顶点的顺序不同。但是,它们与 0-2, 1-2 不同,即使它们与它同构。请注意,后一个图包含边 0-2,而前两个图不包含 - 因此它们的边集不同。

参数: 

graph1:

第一个图对象。

graph2:

第二个图对象。

res:

结果将存储在此处。

返回值: 

错误代码。

时间复杂度:O(E),图中边的数量。

另请参阅: 

igraph_isomorphic() 用于测试两个图是否同构。