用于使用 igraph C 库
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()
。
igraph 具有简单且一致的界面。大多数函数会检查其输入的有效性,并在出现问题时显示信息性错误消息。为了支持这一点,大多数函数会返回错误代码。在基本用法中,可以忽略此代码,因为默认行为是在出错时立即中止程序。有关此主题的更多信息,请参阅关于错误处理的部分。
结果通常通过输出参数返回,即指向将写入结果的数据结构的指针。在几乎所有情况下,都应预先初始化此数据结构。一些简单的函数直接通过其返回值传达结果 - 这些函数永远不会遇到错误。
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 的大小映射到 d
、ld
或 lld
,并且您必须在 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_t 和 igraph_uint_t 的上限和下限由名为 IGRAPH_INTEGER_MIN
、IGRAPH_INTEGER_MAX
、IGRAPH_UINT_MIN
和 IGRAPH_UINT_MAX
的常量提供。
这是 igraph 中的最基本 API。所有其他函数都使用此最小集来创建和操作图。
这是一个非常重要的原则,因为它使得仅通过实现此最小集就可以实现其他数据表示。
本节列出了从 igraph 用户的角度来看,被认为是核心 API 的一部分的所有函数和宏。其中一些函数和宏具有明智的默认实现,这些实现只是调用其他一些核心函数(例如,igraph_empty()
调用 igraph_empty_attrs()
,并带有 null 属性表指针)。如果您希望尝试实现替代数据类型,则您需要替换的实际函数数量较少,因为在大多数情况下您可以依赖相同的默认实现。
igraph_error_t igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed);
最基本的构造函数,所有其他构造函数都应该调用它来创建一个最小的图对象。我们在上述描述中使用术语“空图”应与空图或零图的数学定义区分开来。严格来说,图论中的空图或零图是没有顶点和边的图。但是,通过 igraph 中使用的“空图”,我们指的是具有零个或多个顶点但没有边的图。
参数:
|
指向尚未初始化的图对象的指针。 |
||||
|
图中的顶点数,预计为一个非负整数。 |
||||
|
布尔值;该图是否是有向的。支持的值为
|
返回值:
错误代码: |
时间复杂度:对于具有 |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; }
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()
添加顶点及其属性。
参数:
|
指向尚未初始化的图对象的指针。 |
||||
|
图中的顶点数;预计为一个非负整数。 |
||||
|
布尔值;该图是否是有向的。支持的值为
|
||||
|
图属性。如果不设置图属性,请提供 |
返回值:
错误代码: |
另请参阅:
|
时间复杂度:对于具有 |V| 个顶点(且没有边)的图,为 O(|V|)。
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; }
igraph_vcount
— 图中的顶点数。igraph_ecount
— 图中的边数。igraph_is_directed
— 这是有向图吗?igraph_edge
— 返回边的头部和尾部顶点。igraph_edges
— 给出边序列的头部和尾部顶点。IGRAPH_FROM
— 边的源顶点。IGRAPH_TO
— 边的目标顶点。IGRAPH_OTHER
— 边的另一个端点。igraph_get_eid
— 从边的端点获取边 ID。igraph_get_eids
— 根据相邻顶点返回边 ID。igraph_get_all_eids_between
— 返回一对顶点之间的所有边 ID。igraph_neighbors
— 顶点的相邻顶点。igraph_incident
— 给出顶点的关联边。igraph_degree
— 图中某些顶点的度。igraph_degree_1
— 图中单个顶点的度。
igraph_bool_t igraph_is_directed(const igraph_t *graph);
参数:
|
图。 |
返回值:
布尔值,如果图是有向图,则为 |
时间复杂度: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; }
igraph_error_t igraph_edge( const igraph_t *graph, igraph_integer_t eid, igraph_integer_t *from, igraph_integer_t *to );
参数:
|
图对象。 |
|
边 ID。 |
|
指向 igraph_integer_t 的指针。边的尾部(源)将放在此处。 |
|
指向 igraph_integer_t 的指针。边的头部(目标)将放在此处。 |
返回值:
错误代码。 |
另请参阅:
|
在 0.2 版本中添加。
时间复杂度:O(1)。
igraph_error_t igraph_edges(const igraph_t *graph, igraph_es_t eids, igraph_vector_int_t *edges);
参数:
|
图对象。 |
|
边选择器,边的序列。 |
|
指向初始化的向量的指针。每条边的起始和结束点将放在此处。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(k),其中 k 是选择器中的边数。
#define IGRAPH_FROM(graph,eid)
比 igraph_edge()
更快,但不会进行错误检查:假定 eid
有效。
参数:
|
图。 |
|
边 ID。 |
返回值:
边的源顶点。 |
另请参阅:
如果需要错误检查,请使用 |
#define IGRAPH_TO(graph,eid)
比 igraph_edge()
更快,但不会进行错误检查:假定 eid
有效。
参数:
|
图对象。 |
|
边 ID。 |
返回值:
边的目标顶点。 |
另请参阅:
如果需要错误检查,请使用 |
#define IGRAPH_OTHER(graph,eid,vid)
通常与无向边一起使用,当边的某个端点已知且需要另一个端点时。不会进行错误检查:假定 eid
和 vid
有效。
参数:
|
图对象。 |
|
边 ID。 |
|
边的一个端点的顶点 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);
对于无向图,from
和 to
是可交换的。
参数:
|
图对象。 |
|
指向整数的指针,边 ID 将存储在此处。如果 |
|
边的起点。 |
|
边的终点。 |
|
布尔值,是否在有向图中搜索有向边。对于无向图,此值将被忽略。 |
|
布尔值,如果未找到边是否报告错误。如果为 false,则将 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度: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 版本中添加。
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。
参数:
|
输入图。 |
|
指向初始化的向量的指针,结果存储在此处。它将根据需要调整大小。 |
|
向量,给出要获取边的顶点对。 |
|
布尔值,是否考虑有向图中的边方向。对于无向图,此值将被忽略。 |
|
布尔值,提供非连接顶点是否为错误。如果为 false,则为非连接对返回 -1。 |
返回值:
错误代码。 |
时间复杂度:O(n log(d)),其中 n 是查询的边数,d 是顶点的平均度。
另请参阅:
|
示例 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; }
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 );
对于无向图,source
和 target
是可交换的。
参数:
|
输入图。 |
|
指向初始化的向量的指针,结果存储在此处。它将根据需要调整大小。 |
|
源顶点的 ID |
|
目标顶点的 ID |
|
布尔值,是否考虑有向图中的边方向。对于无向图,此值将被忽略。 |
返回值:
错误代码。 |
时间复杂度:TODO
另请参阅:
|
igraph_error_t igraph_neighbors(const igraph_t *graph, igraph_vector_int_t *neis, igraph_integer_t pnode, igraph_neimode_t mode);
参数:
|
要操作的图。 |
|
此向量将包含结果。应预先初始化该向量,并且将调整其大小。从 igraph 0.4 版本开始,此向量始终排序,顶点 ID 按升序排列。如果一个相邻顶点通过多条边连接,则该相邻顶点将被多次返回。 |
|
要搜索相邻顶点的节点的 ID。 |
|
定义在有向图中搜索相邻顶点的方式。它可以具有以下值: |
返回值:
错误代码: |
时间复杂度: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; }
igraph_error_t igraph_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t pnode, igraph_neimode_t mode);
参数:
|
图对象。 |
|
初始化的向量。将调整其大小以容纳结果。 |
|
顶点 ID。 |
|
指定对于有向图包括哪些类型的边。 |
返回值:
错误代码。 |
在 0.2 版本中添加。
时间复杂度:O(d),到 pnode
的关联边数。
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()
。
参数:
|
图。 |
|
整数向量,将包含结果。应初始化它,并且将调整其大小以适合。 |
|
顶点选择器,给出要计算度的顶点 ID。 |
|
定义有向图的度的类型。有效模式为: |
|
布尔值,给出是否应计算自循环。 |
返回值:
错误代码: |
时间复杂度:如果 loops
为 true
,则为 O(v),否则为 O(v*d)。v 是要计算度的顶点数,d 是它们的(平均)度。
另请参阅:
|
示例 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; }
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()
比调用此函数更有效。
参数:
|
图。 |
|
指向将存储计算度的整数的指针。 |
|
将计算度的顶点。 |
|
定义有向图的度的类型。有效模式为: |
|
布尔值,给出是否应计算自循环。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:如果 loops
为 true
,则为 O(1),否则为 O(d),其中 d 是度。
igraph_error_t igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to);
对于有向图,边从 from
指向 to
。
请注意,如果要向一个大图添加多条边,则一条一条地添加效率低下,最好将它们收集到一个向量中,并通过单个 igraph_add_edges()
调用添加所有边。
参数:
|
图。 |
|
边的第一个顶点的 ID。 |
|
边的第二个顶点的 ID。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),边数加上顶点数。
igraph_error_t igraph_add_edges(igraph_t *graph, const igraph_vector_int_t *edges, void *attr);
这些边在向量中给出,前两个元素定义第一条边(对于有向图,顺序为 from
、to
)。该向量应包含偶数个整数,介于零和图中的顶点数减一之间(包括端点)。如果您还想添加新顶点,请先调用 igraph_add_vertices()
。
参数:
|
将添加边的图。 |
|
边本身。 |
|
新边的属性。如果不需要边属性,则可以在此处提供空指针。 |
返回值:
错误代码: |
此函数使所有迭代器失效。
时间复杂度: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; }
igraph_error_t igraph_add_vertices(igraph_t *graph, igraph_integer_t nv, void *attr);
此函数使所有迭代器失效。
参数:
|
要扩展的图对象。 |
|
指定要添加的顶点数的非负整数。 |
|
新顶点的属性。如果不需要顶点属性,则可以在此处提供空指针。 |
返回值:
错误代码: |
时间复杂度: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; }
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; }
igraph_error_t igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices);
此函数会更改顶点的 ID(除非在某些非常特殊的情况下,但无论如何都不应依赖这些情况)。
此函数使所有迭代器失效。
参数:
|
要操作的图。 |
|
要删除的顶点的 ID,以向量形式表示。该向量可能多次包含相同的 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; }
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
参数获取反向映射。
此函数使所有迭代器失效。
参数:
|
要操作的图。 |
|
要删除的顶点的 ID,以向量形式表示。该向量可能多次包含相同的 ID。 |
|
一个可选的向量指针,提供从删除之前的顶点 ID 到删除之后的顶点 ID 的映射,再加 1。零用于表示在操作期间删除的顶点。如果您不感兴趣,可以在此处提供 |
|
一个可选的向量指针,提供从删除之后的顶点 ID 到删除之前的顶点 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; }
#define IGRAPH_VCOUNT_MAX
此常量的值比 IGRAPH_INTEGER_MAX
小 1。当 igraph 以 32 位模式编译时,这意味着您最多只能有 231 – 2(大约 21 亿)个顶点。在 64 位模式下,限制为 263 – 2,因此您更有可能由于其他原因而遇到内存不足的问题,然后再达到此限制。
#define IGRAPH_ECOUNT_MAX
此常量的值是 IGRAPH_INTEGER_MAX
的一半。当 igraph 以 32 位模式编译时,这意味着您最多只能有大约 230(大约 10.7 亿)个顶点。在 64 位模式下,限制约为 262,因此您更有可能由于其他原因而遇到内存不足的问题,然后再达到此限制。
igraph_error_t igraph_expand_path_to_pairs(igraph_vector_int_t* path);
当您在图中有一个顶点 ID 序列,并且想要检索它们之间边的 ID 时,此函数很有用。该函数会复制向量中除第一个和最后一个元素之外的所有元素,从而有效地将路径转换为可以传递给 igraph_get_eids()
的顶点 ID 向量。
参数:
|
输入向量。它将在原地修改,并且会根据需要调整大小。当向量包含少于两个顶点 ID 时,它将被清除。 |
返回值:
错误代码:如果没有足够的内存来扩展向量,则为 |
void igraph_invalidate_cache(const igraph_t* graph);
igraph 图在其内部数据结构中缓存关于自身的一些基本属性。此函数会使缓存的内容无效,并强制在下次需要时重新计算缓存的属性。
在正常使用期间,您不需要调用此函数;但是,如果我们怀疑您在 igraph 的缓存处理中遇到了错误,我们可能会要求您显式调用此函数。无效缓存条目的一个明显的迹象是,缓存的 igraph 函数(例如 igraph_is_dag()
或 igraph_is_simple()
)的结果在缓存失效前后不同。
参数:
|
要使其缓存失效的图。 |
时间复杂度:O(1)。
igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *res);
如果两个图具有相同的顶点和边集,则认为它们是相同的。相同的图在 igraph 中可能具有多个不同的表示形式,因此需要此函数。
此函数验证两个图是否具有相同的方向性,相同的顶点数,并且当以顶点索引的形式写入时,它们是否包含完全相同的边(无论其顺序如何)。不考虑图属性。
此概念与同构不同。例如,图 0-1, 2-1
和 1-2, 0-1
被认为是相同的,因为它们仅在它们的边列表的顺序和无向边中顶点的顺序不同。但是,它们与 0-2, 1-2
不同,即使它们与它同构。请注意,后一个图包含边 0-2
,而前两个图不包含 - 因此它们的边集不同。
参数:
|
第一个图对象。 |
|
第二个图对象。 |
|
结果将存储在此处。 |
返回值:
错误代码。 |
时间复杂度:O(E),图中边的数量。
另请参阅:
|
← 第 3 章。 教程 | 第 5 章。 错误处理 → |