用于使用 igraph C 库
igraph_error_t igraph_disjoint_union(igraph_t *res, const igraph_t *left, const igraph_t *right);
首先,第二个图的顶点将使用新的顶点 ID 重新标记,以形成两个不相交的顶点 ID 集合,然后形成两个图的并集。如果两个图分别具有 |V1| 和 |V2| 个顶点以及 |E1| 和 |E2| 条边,则新图将具有 |V1|+|V2| 个顶点和 |E1|+|E2| 条边。
图的顶点和边的顺序将被保留。换句话说,第一个图的顶点和边的 ID 映射到新图中的相同值,而第二个图的顶点和边的 ID 映射到递增第一个图的顶点和边的计数后的 ID。
两个图需要具有相同的方向性,即都是有向图或都是无向图。
此函数的当前版本无法处理图、顶点和边的属性,它们将丢失。
参数:
|
指向未初始化的图对象的指针,结果将存储在此处。 |
|
第一个图。 |
|
第二个图。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V1|+|V2|+|E1|+|E2|)。
示例 28.1. 文件 examples/simple/igraph_disjoint_union.c
#include <igraph.h> #include <stdio.h> int main(void) { igraph_t left, right, uni; igraph_vector_ptr_t glist; igraph_integer_t i, n; igraph_small(&left, 4, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,2, 2,3, -1); igraph_small(&right, 5, IGRAPH_UNDIRECTED, 0,1, 1,2, 2,2, 2,4, -1); igraph_disjoint_union(&uni, &left, &right); igraph_write_graph_edgelist(&uni, stdout); printf("\n"); igraph_destroy(&left); igraph_destroy(&right); igraph_destroy(&uni); /* Empty graph list; the result is the directed null graph. */ igraph_vector_ptr_init(&glist, 0); igraph_disjoint_union_many(&uni, &glist); if (!igraph_is_directed(&uni) || igraph_vcount(&uni) != 0) { return 1; } igraph_vector_ptr_destroy(&glist); igraph_destroy(&uni); /* Non-empty graph list. */ igraph_vector_ptr_init(&glist, 10); n = igraph_vector_ptr_size(&glist); for (i = 0; i < n; i++) { VECTOR(glist)[i] = calloc(1, sizeof(igraph_t)); igraph_small(VECTOR(glist)[i], 2, IGRAPH_DIRECTED, 0,1, 1,0, -1); } if (!igraph_is_directed(&uni)) { return 2; } igraph_disjoint_union_many(&uni, &glist); igraph_write_graph_edgelist(&uni, stdout); printf("\n"); /* Destroy and free the graph list. */ n = igraph_vector_ptr_size(&glist); for (i = 0; i < n; i++) { igraph_destroy(VECTOR(glist)[i]); free(VECTOR(glist)[i]); } igraph_vector_ptr_destroy(&glist); igraph_destroy(&uni); return 0; }
igraph_error_t igraph_disjoint_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs);
首先,图中的顶点将使用新的顶点 ID 重新标记,以具有成对不相交的顶点 ID 集合,然后形成图的并集。结果中的顶点和边的数量是图中顶点和边的总数。
输入图的顶点和边的顺序在输出图中保留。
所有图需要具有相同的方向性,即全部有向或全部无向。如果图列表的长度为零,则结果将是一个没有顶点的有向图。
此函数的当前版本无法处理图、顶点和边的属性,它们将丢失。
参数:
|
指向未初始化的图对象的指针,操作的结果将存储在此处。 |
|
指针向量,包含指向已初始化的图对象的指针。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),结果中顶点数加上边数。
igraph_error_t igraph_join(igraph_t *res, const igraph_t *left, const igraph_t *right);
此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。
首先,第二个图的顶点将使用新的顶点 ID 重新标记,以具有两个不相交的顶点 ID 集合,然后形成两个图的并集。最后,第一个图的顶点将添加与第二个图的每个顶点的边。如果两个图分别具有 |V1| 和 |V2| 个顶点以及 |E1| 和 |E2| 条边,则新图将具有 |V1|+|V2| 个顶点和 |E1|+|E2|+|V1|*|V2| 条边。
图的顶点顺序将被保留。换句话说,第一个图的顶点 ID 映射到新图中的相同值,而第二个图的顶点 ID 映射到递增第一个图的顶点计数后的 ID。新边将与共享来自顶点的其他边分组。
两个图需要具有相同的方向性,即都是有向图或都是无向图。如果两个图都是有向图,则对于图 G1、G2 中的每个顶点 v、u,我们添加边 (v, u), (u, v) 以保持完整性。
此函数的当前版本无法处理图、顶点和边的属性,它们将丢失。
参数:
|
指向未初始化的图对象的指针,结果将存储在此处。 |
|
第一个图。 |
|
第二个图。 |
返回值:
错误代码。 |
时间复杂度:O(|V1|*|V2|+|E1|+|E2|)。
igraph_error_t igraph_union( igraph_t *res, const igraph_t *left, const igraph_t *right, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2);
结果中的顶点数是两个参数图中较大图的顶点数。结果图包含至少在一个操作数图中存在的边。
操作数图的方向性必须相同。
边的多重性通过取输入图中两个多重性中的较大值来处理。换句话说,如果第一个图在顶点对 (u, v) 之间有 N 条边,第二个图有 M 条边,则结果图将在它们之间具有 max(N, M) 条边。
参数:
|
指向未初始化的图对象的指针,结果将存储在此处。 |
|
第一个图。 |
|
第二个图。 |
|
指向已初始化的向量或空指针的指针。如果不是空指针,它将包含从第一个参数图( |
|
与 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),|V| 是顶点数,|E| 是结果图中的边数。
示例 28.2. 文件 examples/simple/igraph_union.c
#include <igraph.h> #include <stdio.h> int main(void) { igraph_t left, right, uni; igraph_vector_int_t edge_map1, edge_map2; igraph_vector_int_init(&edge_map1, 0); igraph_vector_int_init(&edge_map2, 0); igraph_small(&left, 4, IGRAPH_DIRECTED, 0,1, 1,2, 2,2, 2,3, 2,3, 3,2, -1); igraph_small(&right, 6, IGRAPH_DIRECTED, 0,1, 1,2, 2,2, 2,3, 5,2, -1); igraph_union(&uni, &left, &right, &edge_map1, &edge_map2); igraph_write_graph_edgelist(&uni, stdout); igraph_vector_int_print(&edge_map1); igraph_vector_int_print(&edge_map2); igraph_destroy(&uni); igraph_destroy(&left); igraph_destroy(&right); igraph_vector_int_destroy(&edge_map2); igraph_vector_int_destroy(&edge_map1); return 0; }
igraph_error_t igraph_union_many( igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_int_list_t *edgemaps );
结果图将包含与参数中最大的图一样多的顶点,如果一条边至少是一个操作数图的一部分,则它将包含在结果图中。
结果图中的顶点数将是参数图中最大顶点数。
参数图的方向性必须相同。如果图列表的长度为零,则结果将是一个没有顶点的有向图。
边的多重性通过取输入图中同一顶点对 (u, v) 的所有多重性的最大值来处理;这将是结果图中 (u, v) 的多重性。
参数:
|
指向未初始化的图对象的指针,这将包含结果。 |
|
指针向量,包含指向并集运算符的操作数的指针,当然是图对象。 |
|
如果不是空指针,则它必须是已初始化的整数向量列表,并且从图到结果图的边的映射将存储在此处,顺序与 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),|V| 是最大图中的顶点数,|E| 是结果图中的边数。
igraph_error_t igraph_intersection( igraph_t *res, const igraph_t *left, const igraph_t *right, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2);
结果图仅包含第一个图和第二个图中都存在的边。结果图中的顶点数与两个参数中较大图的顶点数相同。
操作数图的方向性必须相同。
边的多重性通过取输入图中两个多重性中的较小值来处理。换句话说,如果第一个图在顶点对 (u, v) 之间有 N 条边,第二个图有 M 条边,则结果图将在它们之间具有 min(N, M) 条边。
参数:
|
指向未初始化的图对象的指针。这将包含操作的结果。 |
|
第一个操作数,一个图对象。 |
|
第二个操作数,一个图对象。 |
|
空指针,或已初始化的向量。如果是后者,则从结果图的边到 |
|
空指针,或已初始化的向量。与 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),|V| 是节点数,|E| 是两个图中较小图中的边数。(包含较少顶点的图被认为是较小的。)
示例 28.3. 文件 examples/simple/igraph_intersection.c
#include <igraph.h> void print_vector(igraph_vector_t *v) { igraph_integer_t i, l = igraph_vector_size(v); for (i = 0; i < l; i++) { printf(" %" IGRAPH_PRId "", (igraph_integer_t) VECTOR(*v)[i]); } printf("\n"); } int main(void) { igraph_t left, right, isec; igraph_vector_int_t v; igraph_vector_ptr_t glist; igraph_t g1, g2, g3; igraph_vector_int_t edge_map1, edge_map2; igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, -1); igraph_create(&left, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 1, 0, 5, 4, 1, 2, 3, 2, -1); igraph_create(&right, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init(&edge_map1, 0); igraph_vector_int_init(&edge_map2, 0); igraph_intersection(&isec, &left, &right, &edge_map1, &edge_map2); igraph_vector_int_init(&v, 0); igraph_get_edgelist(&isec, &v, 0); printf("---\n"); igraph_vector_int_print(&v); igraph_vector_int_print(&edge_map1); igraph_vector_int_print(&edge_map2); printf("---\n"); igraph_vector_int_destroy(&v); igraph_destroy(&left); igraph_destroy(&right); igraph_destroy(&isec); igraph_vector_int_destroy(&edge_map1); igraph_vector_int_destroy(&edge_map2); /* empty graph list */ igraph_vector_ptr_init(&glist, 0); igraph_intersection_many(&isec, &glist, 0); if (igraph_vcount(&isec) != 0 || !igraph_is_directed(&isec)) { return 1; } igraph_destroy(&isec); igraph_vector_ptr_destroy(&glist); /* graph list with an empty graph */ igraph_vector_ptr_init(&glist, 3); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, -1); igraph_create(&g1, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, -1); igraph_create(&g2, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_empty(&g3, 10, IGRAPH_DIRECTED); VECTOR(glist)[0] = &g1; VECTOR(glist)[1] = &g2; VECTOR(glist)[2] = &g3; igraph_intersection_many(&isec, &glist, 0); if (igraph_ecount(&isec) != 0 || igraph_vcount(&isec) != 10) { return 2; } igraph_destroy(&g1); igraph_destroy(&g2); igraph_destroy(&g3); igraph_destroy(&isec); igraph_vector_ptr_destroy(&glist); /* "proper" graph list */ igraph_vector_ptr_init(&glist, 3); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, -1); igraph_create(&g1, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, 3, 2, 4, 5, 6, 5, -1); igraph_create(&g2, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 2, 3, 1, 0, 1, 2, 3, 2, 4, 5, 6, 5, 2, 3, -1); igraph_create(&g3, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); VECTOR(glist)[0] = &g1; VECTOR(glist)[1] = &g2; VECTOR(glist)[2] = &g3; igraph_intersection_many(&isec, &glist, 0); igraph_write_graph_edgelist(&isec, stdout); igraph_destroy(&g1); igraph_destroy(&g2); igraph_destroy(&g3); igraph_destroy(&isec); igraph_vector_ptr_destroy(&glist); return 0; }
igraph_error_t igraph_intersection_many( igraph_t *res, const igraph_vector_ptr_t *graphs, igraph_vector_int_list_t *edgemaps );
此函数计算存储在 graphs
参数中的图的交集。只有 graphs
中每个图的一部分的边将包含在结果图中。
结果图中的顶点数将是参数图中最大顶点数。
参数图的方向性必须相同。如果图列表的长度为零,则结果将是一个没有顶点的有向图。
边的多重性通过取输入图中同一顶点对 (u, v) 的所有多重性的最小值来处理;这将是结果图中 (u, v) 的多重性。
参数:
|
指向未初始化的图对象的指针,操作的结果将存储在此处。 |
|
指针向量,包含指向图对象的指针,交集运算符的操作数。 |
|
如果不是空指针,则它必须是已初始化的整数向量列表,并且从图到结果图的边的映射将存储在此处,顺序与 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),|V| 是顶点数,|E| 是最小图(即具有较少顶点的图)中的边数。
igraph_error_t igraph_difference(igraph_t *res, const igraph_t *orig, const igraph_t *sub);
结果中的顶点数是原始图,即左侧第一个操作数中的顶点数。在结果图中,只有 orig
中的边将包含在 sub
中不存在。
参数:
|
指向未初始化的图对象的指针,结果将存储在此处。 |
|
运算符的左操作数,一个图对象。 |
|
运算符的右操作数,一个图对象。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|+|E|),|V| 是较小图中的顶点数,|E| 是结果图中的边数。
示例 28.4. 文件 examples/simple/igraph_difference.c
#include <igraph.h> int main(void) { igraph_t orig, sub, diff; igraph_vector_int_t v; /* Subtract from itself */ printf("subtract itself\n"); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 1, 4, 5, -1); igraph_create(&orig, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_difference(&diff, &orig, &orig); igraph_write_graph_edgelist(&diff, stdout); if (igraph_ecount(&diff) != 0 || igraph_vcount(&diff) != igraph_vcount(&orig)) { return 1; } igraph_destroy(&orig); igraph_destroy(&diff); /* Same for undirected graph */ printf("subtract itself, undirected\n"); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 1, 4, 5, -1); igraph_create(&orig, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 1, 0, 1, 2, 2, 1, 4, 5, -1); igraph_create(&sub, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_difference(&diff, &orig, &sub); igraph_write_graph_edgelist(&diff, stdout); if (igraph_ecount(&diff) != 0 || igraph_vcount(&diff) != igraph_vcount(&orig)) { return 2; } igraph_destroy(&orig); igraph_destroy(&sub); igraph_destroy(&diff); /* Subtract the empty graph */ printf("subtract empty\n"); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 1, 4, 5, -1); igraph_create(&orig, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_empty(&sub, 3, IGRAPH_DIRECTED); igraph_difference(&diff, &orig, &sub); igraph_write_graph_edgelist(&diff, stdout); if (igraph_ecount(&diff) != igraph_ecount(&orig) || igraph_vcount(&diff) != igraph_vcount(&orig)) { return 3; } igraph_destroy(&orig); igraph_destroy(&sub); igraph_destroy(&diff); /* A `real' example */ printf("real example\n"); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 1, 4, 5, 8, 9, -1); igraph_create(&orig, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 5, 4, 2, 1, 6, 7, -1); igraph_create(&sub, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_difference(&diff, &orig, &sub); igraph_write_graph_edgelist(&diff, stdout); igraph_destroy(&diff); igraph_destroy(&orig); igraph_destroy(&sub); /* undirected version */ printf("real example, undirected\n"); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 1, 4, 5, 8, 9, 8, 10, 8, 13, 8, 11, 8, 12, -1); igraph_create(&orig, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 5, 4, 2, 1, 6, 7, 8, 10, 8, 13, -1); igraph_create(&sub, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_difference(&diff, &orig, &sub); igraph_write_graph_edgelist(&diff, stdout); igraph_destroy(&diff); igraph_destroy(&orig); igraph_destroy(&sub); /* undirected version with loop edge, tests Github issue #597 */ printf("Github issue #597, undirected\n"); igraph_vector_int_init_int_end(&v, -1, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 0, -1); igraph_create(&orig, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 0, -1); igraph_create(&sub, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_difference(&diff, &orig, &sub); igraph_write_graph_edgelist(&diff, stdout); igraph_destroy(&diff); igraph_destroy(&orig); igraph_destroy(&sub); return 0; }
igraph_error_t igraph_complementer(igraph_t *res, const igraph_t *graph, igraph_bool_t loops);
补图意味着所有不属于原始图的边都将包含在结果中。
参数:
|
指向未初始化的图对象的指针。 |
|
原始图。 |
|
是否将环边添加到补图中。 |
返回值:
错误代码。 |
另请参阅:
时间复杂度:O(|V|+|E1|+|E2|),|V| 是图中的顶点数,|E1| 是原始图中的边数,|E2| 是补图中的边数。
示例 28.5. 文件 examples/simple/igraph_complementer.c
#include <igraph.h> int main(void) { igraph_t g1, g2; /* complementer of the empty graph */ igraph_empty(&g1, 5, IGRAPH_DIRECTED); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* the same without loops */ igraph_empty(&g1, 5, IGRAPH_DIRECTED); igraph_complementer(&g2, &g1, IGRAPH_NO_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* complementer of the full graph */ igraph_full(&g1, 5, IGRAPH_DIRECTED, IGRAPH_LOOPS); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); if (igraph_ecount(&g2) != 0) { return 1; } igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* complementer of the full graph, results loops only */ igraph_full(&g1, 5, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /************** * undirected * *************/ /* complementer of the empty graph */ igraph_empty(&g1, 5, IGRAPH_UNDIRECTED); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* the same without loops */ igraph_empty(&g1, 5, IGRAPH_UNDIRECTED); igraph_complementer(&g2, &g1, IGRAPH_NO_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* complementer of the full graph */ igraph_full(&g1, 5, IGRAPH_UNDIRECTED, IGRAPH_LOOPS); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); if (igraph_ecount(&g2) != 0) { return 1; } igraph_destroy(&g1); igraph_destroy(&g2); printf("---\n"); /* complementer of the full graph, results loops only */ igraph_full(&g1, 5, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS); igraph_complementer(&g2, &g1, IGRAPH_LOOPS); igraph_write_graph_edgelist(&g2, stdout); igraph_destroy(&g1); igraph_destroy(&g2); return 0; }
igraph_error_t igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t *g2, igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2);
图的组合包含与两个操作数中较大的图相同数量的顶点。当且仅当存在一个顶点 k,使得第一个图包含一条 (i,k) 边,第二个图包含一条 (k,j) 边时,它才包含一条 (i,j) 边。
当然,这正是两个二元关系的组合。
两个图必须具有相同的方向性,否则该函数将返回错误。请注意,对于无向图,根据定义,两个关系是对称的。
参数:
|
指向未初始化的图对象的指针,结果将存储在此处。 |
|
第一个操作数,一个图对象。 |
|
第二个操作数,另一个图对象。 |
|
如果不是空指针,则它必须是指向已初始化向量的指针,并且从结果图的边到第一个图的边的映射存储在此处。 |
|
如果不是空指针,则它必须是指向已初始化向量的指针,并且从结果图的边到第二个图的边的映射存储在此处。 |
返回值:
错误代码。 |
时间复杂度:O(|V|*d1*d2),|V| 是第一个图中的顶点数,d1 和 d2 是第一个图和第二个图中的平均度。
示例 28.6. 文件 examples/simple/igraph_compose.c
#include <igraph.h> int main(void) { igraph_t g1, g2, res; igraph_vector_int_t v; igraph_vector_int_t map1, map2; igraph_vector_int_init(&map1, 0); igraph_vector_int_init(&map2, 0); /* composition with the empty graph */ igraph_empty(&g1, 5, IGRAPH_DIRECTED); igraph_full(&g2, 5, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS); igraph_compose(&res, &g1, &g2, &map1, &map2); if (igraph_ecount(&res) != 0) { return 1; } if (igraph_vector_int_size(&map1) != 0 || igraph_vector_int_size(&map2) != 0) { return 11; } igraph_destroy(&res); igraph_compose(&res, &g2, &g1, &map1, &map2); if (igraph_ecount(&res) != 0) { return 2; } if (igraph_vector_int_size(&map1) != 0 || igraph_vector_int_size(&map2) != 0) { return 12; } igraph_destroy(&res); igraph_destroy(&g1); igraph_destroy(&g2); /* same but undirected */ igraph_empty(&g1, 5, IGRAPH_UNDIRECTED); igraph_full(&g2, 5, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS); igraph_compose(&res, &g1, &g2, &map1, &map2); if (igraph_ecount(&res) != 0) { return 1; } if (igraph_vector_int_size(&map1) != 0 || igraph_vector_int_size(&map2) != 0) { return 11; } igraph_destroy(&res); igraph_compose(&res, &g2, &g1, &map1, &map2); if (igraph_ecount(&res) != 0) { return 2; } if (igraph_vector_int_size(&map1) != 0 || igraph_vector_int_size(&map2) != 0) { return 12; } igraph_destroy(&res); igraph_destroy(&g1); igraph_destroy(&g2); /* proper directed graph */ igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 5, 6, -1); igraph_create(&g1, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 2, 4, 5, 6, -1); igraph_create(&g2, &v, 0, IGRAPH_DIRECTED); igraph_vector_int_destroy(&v); igraph_compose(&res, &g1, &g2, &map1, &map2); igraph_write_graph_edgelist(&res, stdout); igraph_vector_int_print(&map1); igraph_vector_int_print(&map2); igraph_destroy(&res); igraph_destroy(&g1); igraph_destroy(&g2); /* undirected graph */ igraph_vector_int_init_int_end(&v, -1, 0, 1, 1, 2, 5, 6, -1); igraph_create(&g1, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_vector_int_init_int_end(&v, -1, 0, 1, 0, 4, 5, 6, -1); igraph_create(&g2, &v, 0, IGRAPH_UNDIRECTED); igraph_vector_int_destroy(&v); igraph_compose(&res, &g1, &g2, &map1, &map2); igraph_write_graph_edgelist(&res, stdout); igraph_vector_int_print(&map1); igraph_vector_int_print(&map2); igraph_destroy(&res); igraph_destroy(&g1); igraph_destroy(&g2); igraph_vector_int_destroy(&map2); igraph_vector_int_destroy(&map1); return 0; }
igraph_connect_neighborhood
— 将每个顶点连接到其邻域。igraph_contract_vertices
— 用一个顶点替换多个顶点。igraph_graph_power
— 图的 k 次幂。igraph_product
— 两个图的图积,根据选择的积类型。igraph_induced_subgraph
— 创建由指定顶点导出的子图。igraph_induced_subgraph_map
— 创建一个导出的子图并返回来自原始图的映射。igraph_induced_subgraph_edges
— 导出的子图中包含的边。igraph_linegraph
— 创建图的线图。igraph_simplify
— 从图中删除环和/或多重边。igraph_subgraph_from_edges
— 创建具有指定边及其端点的子图。igraph_reverse_edges
— 反转有向图的一些边。
igraph_error_t igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order, igraph_neimode_t mode);
此函数将新边添加到输入图中。每个顶点都连接到从它最多 order
步可到达的所有顶点(除非已经存在连接)。
请注意,输入图已就地修改,不会创建新图。如果您也想保留原始图,请调用 igraph_copy()
。
对于无向图,可达性始终是对称的:如果最多 order
步可以从顶点 B 到达顶点 A,那么反之亦然。在这种情况下,只会添加一个无向 (A,B) 边。
参数:
|
输入图。它将就地修改。 |
|
整数常量,它给出了顶点将连接到源顶点的距离。 |
|
常量,它指定如何对有向图执行邻域搜索。如果 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|*d^k),|V| 是图中的顶点数,d 是平均度,k 是 order
参数。
igraph_error_t igraph_contract_vertices(igraph_t *graph, const igraph_vector_int_t *mapping, const igraph_attribute_combination_t *vertex_comb);
此函数通过将多个顶点合并为一个来修改图。修改后的图中的顶点对应于输入图中的顶点组。不会删除任何边,因此修改后的图通常会具有自环(对应于组内边)和多重边(对应于两个组之间的多个连接)。使用 igraph_simplify()
删除自环并合并多重边。
参数:
|
输入图。它将就地修改。 |
|
一个向量,给出映射。对于原始图中的每个顶点,它应包含其在结果图中的所需 ID。为了不创建“孤立顶点”,即原始图中没有对应顶点的顶点,请确保 ID 是从零开始的连续整数。 |
|
如何处理顶点属性。 |
返回值:
错误代码。 |
时间复杂度:O(|V|+|E|),在顶点数加上边数中是线性的。
示例 28.7. 文件 examples/simple/igraph_contract_vertices.c
#include <igraph.h> /* Create the condensation of a directed graph. * See https://en.wikipedia.org/wiki/Strongly_connected_component#Definitions * This example demonstrates how to write a basic igraph function, complete * with error handling. */ igraph_error_t condensation(const igraph_t *graph, igraph_t *cond) { igraph_vector_int_t membership; /* Data structures such as vector must be initialized in igraph before use. */ IGRAPH_CHECK(igraph_vector_int_init(&membership, 0)); /* Adding the initialized vector to the "finally" stack ensures that it will * be automatically destroyed if an error occurs. */ IGRAPH_FINALLY(igraph_vector_int_destroy, &membership); /* Functions that return an error code can be wrapped in IGRAPH_CHECK to pass that error * up to the caller. */ IGRAPH_CHECK(igraph_connected_components(graph, &membership, /* csize */ NULL, /* no */ NULL, IGRAPH_STRONG)); /* To compute the condensation, we simply contract strongly connected components. * Since igraph_contract_vertices() modifies graphs in-place, we make a copy first. */ IGRAPH_CHECK(igraph_copy(cond, graph)); /* Since we are not done creating the condensation yet, we add 'cond' to the * "finally" stack, so that it will be destroyed if an error occurs. */ IGRAPH_FINALLY(igraph_destroy, cond); /* Contract strongly connected components. */ IGRAPH_CHECK(igraph_contract_vertices(cond, &membership, NULL)); /* igraph_contract_vertices() preserves all edges, some of which become * parallel edges or self-loops after the contraction. We simplify these. */ IGRAPH_CHECK(igraph_simplify(cond, /* remove_multiple */ true, /* remove_loops */ true, NULL)); /* Data structures that are no longer needed must be explicitly destroyed. * If they were added to the "finally" stack, they must be removed explicitly, * in the opposite order to how they were added. IGRAPH_FINALLY_CLEAN removes * the indicated number of entries from the "finally" stack. We remove * 'membership' because it was destroyed, and 'cond' because the responsibility * to destroy it is now with the caller. */ igraph_vector_int_destroy(&membership); IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; /* return with no error */ } int main(void) { igraph_t graph, cond; /* Create a random directed graph with mean degree 2 and compute its condensation. */ igraph_erdos_renyi_game_gnm(&graph, 100, 200, IGRAPH_DIRECTED, IGRAPH_NO_LOOPS); condensation(&graph, &cond); printf("Number of vertices in the condensation: %" IGRAPH_PRId "\n", igraph_vcount(&cond)); igraph_write_graph_edgelist(&cond, stdout); /* Destroy data structures that are no longer needed. */ igraph_destroy(&graph); igraph_destroy(&cond); return 0; }
igraph_error_t igraph_graph_power(const igraph_t *graph, igraph_t *res, igraph_integer_t order, igraph_bool_t directed);
此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。
图 G 的 k 次幂是一个简单图,其中顶点 u
通过一条边连接到 v
,如果 v
在 G 中最多 k 步可从 u
到达。按照惯例,图的零次幂没有边。一次幂与原始图相同,只是删除了多重边和自环。
图幂通常仅为无向图定义。igraph 将此概念扩展到有向图。要在输入中忽略边的方向,请将 directed
参数设置为 false
。在这种情况下,结果将是一个无向图。
图和顶点属性被保留,但边属性被丢弃。
参数:
|
输入图。 |
|
给定 |
|
非负整数,将图提升到的幂。换句话说,距离在 |
|
是否考虑边的方向。 |
返回值:
错误代码。 |
另请参阅:
|
时间复杂度:O(|V|*d^k),|V| 是图中的顶点数,d 是平均度,k 是 order
参数。
igraph_error_t igraph_product(igraph_t *res, const igraph_t *g1, const igraph_t *g2, igraph_product_t type);
此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。
此函数使用由 type
参数选择的图积概念来计算两个图的积。这两个图必须是相同的类型,有向图或无向图。如果需要无向图和有向图的积,请使用 igraph_to_directed()
或 igraph_to_undirected()
将其中一个转换为适当的类型。
乘积图的每个顶点对应于一对 (u, v)
,其中 u
是来自第一个图的顶点,v
是来自第二个图的顶点。因此,乘积图中的顶点数为 |V1| |V2|
,其中 |V1|
和 |V2|
是操作数的顶点集的大小。使用 index = u |V2| + v
将对 (u, v)
映射到乘积图中的唯一顶点索引。
下面详细介绍了支持的图积类型。符号 u ~ v
用于指示顶点 u
和 v
相邻,即存在从 u
到 v
的连接。
|
计算两个图的笛卡尔积。在乘积图中,当且仅当 时间复杂度:O(|V1| |V2| + |V1| |E2| + |V2| |E1|),其中 |V1| 和 |V2| 是顶点数,|E1| 和 |E2| 是操作数的边数。 |
|
计算两个图的张量(分类)积。在乘积图中,当且仅当 时间复杂度:O(|V1| |V2| + |E1| |E2|),其中 |V1| 和 |V2| 是顶点数,|E1| 和 |E2| 是操作数的边数。 |
参数:
|
指向未初始化的图对象的指针。乘积图将存储在此处。 |
|
第一个操作数图。 |
|
第二个操作数图。 |
|
要计算的图积的类型。 |
返回值:
错误代码:如果指定的 |
igraph_error_t igraph_induced_subgraph(const igraph_t *graph, igraph_t *res, const igraph_vs_t vids, igraph_subgraph_implementation_t impl);
此函数收集指定的顶点和它们之间的所有边到新图。由于顶点 ID 始终是从零开始的连续整数,因此创建的子图中的 ID 将与原始图中的 ID 不同。要获取它们之间的映射,请使用 igraph_induced_subgraph_map()
参数:
|
图对象。 |
|
子图,另一个图对象将存储在此处,请不要在此函数调用之前初始化此对象,如果您不再需要它,请调用 |
|
一个顶点选择器,描述要保留哪些顶点。顶点可以在选择器中出现多次,但它只会被考虑一次(即,不可能通过将其 ID 多次添加到选择器来复制顶点)。顶点在顶点选择器中出现的顺序被忽略;返回的子图将始终包含原始图的顶点,并按顶点 ID 的递增顺序排列。 |
|
此参数选择我们在构造新图时应使用的实现。基本上有两种可能性: |
返回值:
错误代码: |
时间复杂度:O(|V|+|E|),|V| 和 |E| 是原始图中顶点和边的数量。
另请参阅:
请同时参考 |
igraph_error_t igraph_induced_subgraph_map(const igraph_t *graph, igraph_t *res, const igraph_vs_t vids, igraph_subgraph_implementation_t impl, igraph_vector_int_t *map, igraph_vector_int_t *invmap);
此函数将指定的顶点以及它们之间的所有边收集到一个新图中。由于顶点 ID 始终是从零开始的连续整数,因此创建的子图中的 ID 将与原始图中的 ID 不同。图和提取的子图中的顶点 ID 之间的映射在 map
和 invmap
中返回。
参数:
|
图对象。 |
|
子图,另一个图对象将存储在此处,请不要在此函数调用之前初始化此对象,如果您不再需要它,请调用 |
|
一个顶点选择器,用于描述要保留哪些顶点。 |
|
此参数选择构造新图时应使用的实现方式。基本上有两种可能性: |
|
返回 |
|
返回 |
返回值:
错误代码: |
时间复杂度:O(|V|+|E|),|V| 和 |E| 是原始图中顶点和边的数量。
另请参阅:
请同时参考 |
igraph_error_t igraph_induced_subgraph_edges(const igraph_t *graph, igraph_vs_t vids, igraph_vector_int_t *edges);
此函数查找那些连接给定列表中顶点的边的 ID,列表在 vids
参数中传递。
参数:
|
图。 |
|
一个顶点选择器,指定构成子图的顶点。 |
|
整数向量。 |
返回值:
错误代码。 |
时间复杂度:O(mv log(nv)),其中 nv 是 vids
中的顶点数,mv 是 vids
中顶点的度数之和。
igraph_error_t igraph_linegraph(const igraph_t *graph, igraph_t *linegraph);
G 无向图的线图 L(G) 定义如下。 L(G) 对于 G 中的每条边都有一个顶点,并且 L(G) 中的两个不同顶点通过一条边连接,如果它们对应的边共享一个端点。 在一个多重图中,如果共享两个端点,则创建两条边。 无向自环的单个顶点被计为两个端点。
G 有向图的线图 L(G) 略有不同:L(G) 对于 G 中的每条边都有一个顶点,并且 L(G) 中的两个顶点通过有向边连接,如果第一个顶点对应边的目标与第二个顶点对应边的源相同。
自环被认为是自相邻的,因此它们在线图中的对应顶点也将具有一个自环,在无向图和有向图中都是如此。
原始图中的边 i 将对应于线图中的顶点 i。
此函数的第一个版本由 Vincent Matossian 贡献,谢谢。
参数:
|
输入图,可以是有向图或无向图。 |
|
指向未初始化的图对象的指针,结果将存储在此处。 |
返回值:
错误代码。 |
时间复杂度:O(|V|+|E|),边数加上顶点数。
igraph_error_t igraph_simplify(igraph_t *graph, igraph_bool_t remove_multiple, igraph_bool_t remove_loops, const igraph_attribute_combination_t *edge_comb);
此函数根据 multiple
和 loops
参数合并平行边并移除自环。 请注意,即使输入已经是简单图,此函数也可能会更改边的顺序。
参数:
|
图对象。 |
|
如果为 true,则将移除多重边。 |
|
如果为 true,则将移除环(自环)。 |
|
如何处理边的属性。 |
返回值:
错误代码:如果内存不足,则为 |
时间复杂度:O(|V|+|E|)。
示例 28.8. 文件 examples/simple/igraph_simplify.c
#include <igraph.h> int main(void) { igraph_t g; /* Multiple edges */ igraph_small(&g, 0, IGRAPH_DIRECTED, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); if (igraph_ecount(&g) != 1) { return 1; } igraph_destroy(&g); /* Loop edges*/ igraph_small(&g, 0, IGRAPH_DIRECTED, 0, 0, 1, 1, 2, 2, 1, 2, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_UNDIRECTED, 0, 0, 1, 1, 2, 2, 1, 2, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); /* Loop & multiple edges */ igraph_small(&g, 0, IGRAPH_DIRECTED, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, -1); igraph_simplify(&g, /* remove_multiple */ true, /* remove_loops */ false, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_UNDIRECTED, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, -1); igraph_simplify(&g, /* remove_multiple */ true, /* remove_loops */ false, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_DIRECTED, 2, 2, 2, 2, 2, 2, 3, 2, -1); igraph_simplify(&g, /* remove_multiple */ false, /* remove_loops */ true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_UNDIRECTED, 3, 3, 3, 3, 3, 4, -1); igraph_simplify(&g, /* remove_multiple */ false, /* remove_loops */ true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_DIRECTED, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); igraph_write_graph_edgelist(&g, stdout); igraph_destroy(&g); igraph_small(&g, 0, IGRAPH_UNDIRECTED, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 2, 3, 3, 2, 3, 2, 3, 2, -1); igraph_simplify(&g, true, true, /*edge_comb=*/ NULL); if (igraph_ecount(&g) != 1) { return 2; } igraph_destroy(&g); return 0; }
igraph_error_t igraph_subgraph_from_edges( const igraph_t *graph, igraph_t *res, const igraph_es_t eids, igraph_bool_t delete_vertices );
此函数将指定的边及其端点收集到一个新图中。 由于图中的边 ID 始终是从零开始的连续整数,因此提取的子图中的边 ID 将与原始图中的边 ID 不同。 如果 delete_vertices
设置为 true
,则还将重新分配顶点 ID。 属性将被保留。
参数:
|
图对象。 |
|
子图,另一个图对象将存储在此处,请不要在此函数调用之前初始化此对象,如果您不再需要它,请调用 |
|
一个边选择器,用于描述要保留哪些边。 |
|
是否也要删除未与任何指定边关联的顶点。 如果为 |
返回值:
错误代码: |
时间复杂度:O(|V|+|E|),|V| 和 |E| 是原始图中顶点和边的数量。
另请参阅:
请同时参考 |
igraph_error_t igraph_reverse_edges(igraph_t *graph, const igraph_es_t eids);
此函数反转有向图的某些边。 修改是就地完成的。 所有属性以及边和顶点的顺序都将被保留。
请注意,很少需要反转所有边,因为几乎所有处理有向图的函数都采用 mode
参数,该参数可以设置为 IGRAPH_IN
以有效地将边视为已反转。
参数:
|
将反转其边的图。 |
|
要反转的边。 传递 |
返回值:
错误代码。 |
时间复杂度:如果反转所有边,则为 O(1),否则为 O(|E|),其中 |E| 是图中的边数。
igraph_error_t igraph_subgraph_edges( const igraph_t *graph, igraph_t *res, const igraph_es_t eids, igraph_bool_t delete_vertices );
自 0.10.3 版本起已弃用。 请不要在新代码中使用此函数; 请改用 igraph_subgraph_from_edges()
。
← 第 27. 章 图的嵌入 | 第 29. 章 将 BLAS、LAPACK 和 ARPACK 用于 igraph 矩阵和图 → |