igraph 参考手册

用于使用 igraph C 库

搜索手册

第 7 章 数据结构库:向量、矩阵和其他数据类型

1. 关于模板类型

本节列出的一些容器类型是为多种基本类型定义的。这类似于 C++ 中的模板和 Ada 中的泛型,但由于 C 语言无法处理,因此它是通过预处理器宏实现的。以下是模板类型及其当前支持的所有基本类型的列表

向量

向量当前为 igraph_real_tigraph_integer_t (int)、char (char)、igraph_bool_t (bool)、igraph_complex_t (complex) 和 void * (ptr) 定义。默认值为 igraph_real_t

矩阵

矩阵当前为 igraph_real_tigraph_integer_t (int)、char (char)、igraph_bool_t (bool) 和 igraph_complex_t (complex) 定义。默认值为 igraph_real_t

array3

Array3 当前为 igraph_real_tigraph_integer_t (int)、char (char) 和 igraph_bool_t (bool) 定义。默认值为 igraph_real_t

栈当前为 igraph_real_tigraph_integer_t (int)、char (char) 和 igraph_bool_t (bool) 定义。默认值为 igraph_real_t

双端队列

Dqueue 当前为 igraph_real_tigraph_integer_t (int)、char (char) 和 igraph_bool_t (bool) 定义。默认值为 igraph_real_t

堆当前为 igraph_real_tigraph_integer_t (int)、char (char) 定义。此外,还提供最大堆和最小堆。默认值为 igraph_real_t 最大堆。

向量列表

向量列表当前为保存 igraph_real_tigraph_integer_t (int) 的向量定义。默认值为 igraph_real_t

矩阵列表

矩阵列表当前仅为保存 igraph_real_t 的矩阵定义。

基本元素的名称(在括号中)会添加到函数名称中,默认类型除外。

一些示例

  • igraph_vector_tigraph_real_t 元素的向量。其函数为 igraph_vector_initigraph_vector_destroyigraph_vector_sort 等。

  • igraph_vector_bool_tigraph_bool_t 元素的向量;使用 igraph_vector_bool_init 初始化,使用 igraph_vector_bool_destroy 销毁,等等。

  • igraph_heap_t 是一个带有 igraph_real_t 元素的最大堆。相应的函数为 igraph_heap_initigraph_heap_pop 等。

  • igraph_heap_min_t 是一个带有 igraph_real_t 元素的最小堆。相应的函数名为 igraph_heap_min_initigraph_heap_min_pop 等。

  • igraph_heap_int_t 是一个带有 igraph_integer_t 元素的最大堆。其函数具有 igraph_heap_int_ 前缀。

  • igraph_heap_min_int_t 是一个包含 igraph_integer_t 元素的最小堆。其函数具有 igraph_heap_min_int_ 前缀。

  • igraph_vector_list_t 是一个(浮点)向量列表;此数据结构中的每个元素都是 igraph_vector_t。类似地,igraph_matrix_list_t 是一个(浮点)矩阵列表;此数据结构中的每个元素都是 igraph_matrix_t

  • igraph_vector_int_list_t 是一个整数向量列表;此数据结构中的每个元素都是 igraph_vector_int_t

请注意,VECTORMATRIX 宏可以用于所有向量和矩阵类型。VECTOR 不能用于向量列表,只能用于列表中的单个向量。

2. 向量

2.1. 关于 igraph_vector_t 对象

igraph_vector_t 数据类型是一个简单而高效的接口,用于包含数字的数组。它类似于(但比)C++ 标准库中的 vector 模板。

存在多种 igraph_vector_t 变体;基本变体存储双精度数,但也存在用于整数(类型为 igraph_integer_t)、布尔值(类型为 igraph_bool_t)等的 igraph_vector_int_tigraph_vector_bool_t。向量在 igraph 中被广泛使用;所有期望或返回数字列表的函数都使用 igraph_vector_tigraph_vector_int_t 来实现此目的。整数向量通常用于向量应该保存顶点或边标识符时,而 igraph_vector_t 用于向量应该保存小数或无穷大时。

igraph_vector_t 类型及其变体通常使用 O(n) 空间来存储 n 个元素。有时它们会使用更多空间,这是因为向量可以缩小,但即使它们缩小,当前的实现也不会释放任何内存。

igraph_vector_t 对象及其变体中的元素从零开始索引,我们在此遵循通常的 C 约定。

向量的元素始终占用一块内存,可以使用 VECTOR 宏查询此内存块的起始地址。这样,向量对象可以与标准数学库(如 GNU 科学库)一起使用。

下面针对 igraph_vector_t 描述的几乎所有函数也适用于所有其他向量类型变体。这些变体没有单独记录;如果您需要另一个变体的函数,只需将 vector 替换为 vector_intvector_bool 或类似的名称即可。例如,要初始化类型为 igraph_vector_int_t 的向量,您需要使用 igraph_vector_int_init(),而不是 igraph_vector_init()

2.2. 构造函数和析构函数

igraph_vector_t 对象在使用前必须初始化,这类似于对其调用构造函数。为了您的方便,存在许多 igraph_vector_t 构造函数。igraph_vector_init() 是基本构造函数,它创建一个给定长度的向量,并用零填充每个条目。igraph_vector_init_copy() 创建一个已经存在并初始化的向量的新的相同副本。igraph_vector_init_array() 通过复制一个普通的 C 数组来创建一个向量。igraph_vector_init_range() 创建一个包含增量为 1 的常规序列的向量。

igraph_vector_view() 是一个特殊的构造函数,它允许您将常规 C 数组作为 vector 处理,而无需复制其元素。

如果不再需要 igraph_vector_t 对象,则应通过调用 igraph_vector_t 析构函数 igraph_vector_destroy() 来销毁它以释放其分配的内存。

请注意,由 igraph_vector_view() 创建的向量是特殊的,您绝不能在这些向量上调用 igraph_vector_destroy()

2.2.1. igraph_vector_init — 初始化向量对象(构造函数)。

igraph_error_t igraph_vector_init(igraph_vector_t *v, igraph_integer_t size);

每个向量在使用前都需要初始化,并且存在许多初始化函数或以其他方式调用的构造函数。此函数构造一个给定大小的向量,并将每个条目初始化为 0。请注意,igraph_vector_null() 可用于将向量的每个元素设置为零。但是,如果您想要一个零向量,则使用此函数比创建向量然后调用 igraph_vector_null() 快得多。

由该函数初始化的每个向量对象都应该在其不再需要时销毁(即,为其分配的内存应该释放),igraph_vector_destroy() 函数负责执行此操作。

参数: 

v:

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

大小:

向量的大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:操作系统相关,分配 O(n) 个元素所需的时间量,n 是元素的数量。

2.2.2. igraph_vector_init_array — 从普通 C 数组初始化向量(构造函数)。

igraph_error_t igraph_vector_init_array(
        igraph_vector_t *v, const igraph_real_t *data, igraph_integer_t length);

参数: 

v:

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

数据:

一个普通的 C 数组。

长度:

C 数组的长度。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:操作系统特定,通常为 O(length)。

2.2.3. igraph_vector_init_copy — 从另一个向量对象初始化向量(构造函数)。

igraph_error_t igraph_vector_init_copy(
    igraph_vector_t *to, const igraph_vector_t *from
);

现有向量对象的内容将被复制到新对象。

参数: 

:

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

:

要复制的原始向量对象。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:操作系统相关,通常为 O(n),n 是向量的大小。

2.2.4. igraph_vector_init_range — 使用范围初始化向量。

igraph_error_t igraph_vector_init_range(igraph_vector_t *v, igraph_real_t start, igraph_real_t end);

该向量将包含数字 startstart+1、...、end-1。请注意,根据 C 约定,该范围从左侧闭合,从右侧打开。

参数: 

v:

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

开始:

范围内的下限(包括)。

结束:

范围内的上限(不包括)。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:O(n),向量中的元素数量。

2.2.5. igraph_vector_destroy — 销毁向量对象。

void igraph_vector_destroy(igraph_vector_t *v);

igraph_vector_init() 初始化的所有向量都应由此函数正确销毁。销毁的向量需要通过 igraph_vector_init()igraph_vector_init_array() 或另一个构造函数重新初始化。

参数: 

v:

指向要销毁的(先前初始化的)向量对象的指针。

时间复杂度:操作系统相关。

2.3. 初始化元素

2.3.1. igraph_vector_null — 将向量中的每个元素设置为零。

void igraph_vector_null(igraph_vector_t *v);

请注意,igraph_vector_init() 也将元素设置为零,因此在刚刚初始化的向量上调用此函数没有意义。因此,如果您想要构造一个零向量,则应该使用 igraph_vector_init()

参数: 

v:

向量对象。

时间复杂度:O(n),向量的大小。

2.3.2. igraph_vector_fill — 用常量元素填充向量。

void igraph_vector_fill(igraph_vector_t *v, igraph_real_t e);

将向量的每个元素设置为提供的常量。

参数: 

向量:

要处理的向量。

e:

要填充的元素。

时间复杂度:O(n),向量的大小。

2.3.3. igraph_vector_range — 更新向量以存储范围。

igraph_error_t igraph_vector_range(igraph_vector_t *v, igraph_real_t start, igraph_real_t end);

将向量的元素设置为包含数字 startstart+1、...、end-1。请注意,根据 C 约定,该范围从左侧闭合,从右侧打开。向量将被调整大小以适合该范围。

参数: 

v:

要更新的向量。

开始:

范围内的下限(包括)。

结束:

范围内的上限(不包括)。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:O(n),向量中的元素数量。

2.4. 访问元素

访问向量元素的最好和最有效的方法是使用 VECTOR 宏。此宏可以用于查询和设置 igraph_vector_t 元素。如果您需要一个函数,igraph_vector_get() 查询向量的元素,igraph_vector_set() 设置向量的元素。igraph_vector_get_ptr() 返回元素的地址。

igraph_vector_tail() 返回非空向量的最后一个元素。但是,没有 igraph_vector_head() 函数,因为很容易编写 VECTOR(v)[0] 来代替。

2.4.1. VECTOR — 访问向量的元素。

#define VECTOR(v)

用法

 VECTOR(v)[0] 

要访问向量的第一个元素,您也可以在赋值中使用它,例如

 VECTOR(v)[10] = 5; 

请注意,目前没有范围检查。

参数: 

v:

向量对象。

时间复杂度:O(1)。

2.4.2. igraph_vector_get — 访问向量的元素。

igraph_real_t igraph_vector_get(const igraph_vector_t *v, igraph_integer_t pos);

除非您需要函数,否则请考虑使用 VECTOR 宏以获得更好的性能。

参数: 

v:

igraph_vector_t 对象。

位置:

元素的位置,第一个元素的索引为零。

返回值: 

所需的元素。

另请参阅: 

时间复杂度:O(1)。

2.4.3. igraph_vector_get_ptr — 获取向量的元素的地址。

igraph_real_t* igraph_vector_get_ptr(const igraph_vector_t *v, igraph_integer_t pos);

除非您需要函数,否则请考虑使用 VECTOR 宏以获得更好的性能。

参数: 

v:

igraph_vector_t 对象。

位置:

元素的位置,第一个元素的位置为零。

返回值: 

指向所需元素的指针。

另请参阅: 

时间复杂度:O(1)。

2.4.4. igraph_vector_set — 对向量的元素赋值。

void igraph_vector_set(igraph_vector_t *v, igraph_integer_t pos, igraph_real_t value);

除非您需要函数,否则请考虑使用 VECTOR 宏以获得更好的性能。

参数: 

v:

igraph_vector_t 元素。

位置:

要设置的元素的位置。

:

元素的新值。

另请参阅: 

2.4.5. igraph_vector_tail — 返回向量中的最后一个元素。

igraph_real_t igraph_vector_tail(const igraph_vector_t *v);

在空向量上调用此函数是错误的,结果是未定义的。

参数: 

v:

向量对象。

返回值: 

最后一个元素。

时间复杂度:O(1)。

2.5. 向量视图

2.5.1. igraph_vector_view — 将常规 C 数组作为 igraph_vector_t 处理。

const igraph_vector_t* igraph_vector_view(const igraph_vector_t *v,
        const igraph_real_t *data, igraph_integer_t length);

这是一个特殊的 igraph_vector_t 构造函数。它允许临时将常规 C 数组作为 igraph_vector_t 处理。请确保您不要在由此构造函数创建的对象上调用析构函数 (igraph_vector_destroy())。

参数: 

v:

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

数据:

指针,C 数组。它可能不是 NULL,除非 length 为零。

长度:

C 数组的长度。

返回值: 

指向向量对象的指针,与 v 参数相同,为了方便起见。

时间复杂度:O(1)

2.6. 复制向量

2.6.1. igraph_vector_copy_to — 将向量的内容复制到 C 数组。

void igraph_vector_copy_to(const igraph_vector_t *v, igraph_real_t *to);

C 数组应该有足够的长度。

参数: 

v:

向量对象。

:

C 数组。

时间复杂度:O(n),n 是向量的大小。

2.6.2. igraph_vector_update — 从另一个向量更新向量。

igraph_error_t igraph_vector_update(igraph_vector_t *to,
                                    const igraph_vector_t *from);

此操作后,to 的内容将与 from 的内容完全相同。如果向量 to 最初比 from 短或长,则会调整其大小。

参数: 

:

要更新的向量。

:

要从中更新的向量。

返回值: 

错误代码。

时间复杂度:O(n),from 中的元素数量。

2.6.3. igraph_vector_append — 将一个向量追加到另一个向量。

igraph_error_t igraph_vector_append(igraph_vector_t *to,
                                    const igraph_vector_t *from);

目标向量的大小将被调整(除非 from 为空)。

参数: 

:

要追加到的向量。

:

要追加的向量,它保持不变。

返回值: 

错误代码。

时间复杂度:O(n),新向量中的元素数量。

2.6.4. igraph_vector_swap — 交换两个向量的所有元素。

igraph_error_t igraph_vector_swap(igraph_vector_t *v1, igraph_vector_t *v2);

参数: 

v1:

第一个向量。

v2:

第二个向量。

返回值: 

错误代码。

时间复杂度:O(1)。

2.7. 交换元素

2.7.1. igraph_vector_swap_elements — 交换向量中的两个元素。

igraph_error_t igraph_vector_swap_elements(igraph_vector_t *v,
        igraph_integer_t i, igraph_integer_t j);

请注意,目前不执行范围检查。

参数: 

v:

输入向量。

i:

第一个元素的索引。

j:

第二个元素的索引(可能与第一个元素相同)。

返回值: 

错误代码,目前始终为 IGRAPH_SUCCESS

时间复杂度:O(1)。

2.7.2. igraph_vector_reverse — 反转向量的元素。

igraph_error_t igraph_vector_reverse(igraph_vector_t *v);

第一个元素将是最后一个,最后一个元素将是第一个,依此类推。

参数: 

v:

输入向量。

返回值: 

错误代码,目前始终为 IGRAPH_SUCCESS

另请参阅: 

igraph_vector_reverse_section() 仅反转向量的某个部分。

时间复杂度:O(n),元素数量。

2.7.3. igraph_vector_reverse_section — 反转向量的某个部分的元素。

void igraph_vector_reverse_section(igraph_vector_t *v, igraph_integer_t from, igraph_integer_t to);

参数: 

v:

输入向量。

:

要包含在反转中的第一个元素的索引。

:

不包含在反转中的第一个元素的索引。

另请参阅: 

igraph_vector_reverse() 反转整个向量。

时间复杂度:O(to - from),要反转的元素数量。

2.7.4. igraph_vector_rotate_left — 将向量的元素向左旋转。

void igraph_vector_rotate_left(igraph_vector_t *v, igraph_integer_t n);

将向量的元素向左旋转给定的步数。旋转后,元素索引 n 的索引将为 0。例如,将 (0, 1, 2, 3, 4, 5) 旋转 2 将得到 (2, 3, 4, 5, 0, 1)

参数: 

v:

输入向量。

n:

要旋转的步数。传递负值会向右旋转。

时间复杂度:O(n),元素数量。

2.7.5. igraph_vector_shuffle — 使用 Fisher-Yates 方法就地洗牌向量。

igraph_error_t igraph_vector_shuffle(igraph_vector_t *v);

Fisher-Yates 洗牌确保在使用适当的随机源时,每个排列都是同样可能的。当然,这不适用于伪随机生成器,因为这些生成器的循环小于向量可能排列的数量(如果向量足够长)。

参数: 

v:

向量对象。

返回值: 

错误代码,目前始终为 IGRAPH_SUCCESS

时间复杂度:O(n),向量中的元素数量。

参考

(Fisher & Yates 1963)

R. A. Fisher 和 F. Yates。《生物学、农业和医学研究的统计表。》 Oliver 和 Boyd,第 6 版,1963 年,第 37 页。

(Knuth 1998)

D. E. Knuth。《半数值算法,》卷 2,《计算机编程的艺术。》 Addison-Wesley,第 3 版,1998 年,第 145 页。

示例 7.1. 文件 examples/simple/igraph_fisher_yates_shuffle.c

#include <igraph.h>

#define R_INTEGER(a,b) (igraph_rng_get_integer(igraph_rng_default(), (a), (b)))
#define R_UNIF(a,b) (igraph_rng_get_unif(igraph_rng_default(), (a), (b)))

int main(void) {
    igraph_real_t d;
    igraph_vector_t u, v;
    igraph_integer_t i, k, n;

    /********************************
     * Example usage
     ********************************/

    /* Sequences with one element. Such sequences are trivially permuted.
     * The result of any Fisher-Yates shuffle on a sequence with one element
     * must be the original sequence itself.
     */
    n = 1;
    igraph_vector_init(&v, n);
    igraph_rng_seed(igraph_rng_default(), 42); /* make tests deterministic */
    k = R_INTEGER(-1000, 1000);
    VECTOR(v)[0] = k;
    igraph_vector_shuffle(&v);
    if (VECTOR(v)[0] != k) {
        return 1;
    }
    d = R_UNIF(-1000.0, 1000.0);

    VECTOR(v)[0] = d;
    igraph_vector_shuffle(&v);
    if (VECTOR(v)[0] != d) {
        return 2;
    }
    igraph_vector_destroy(&v);

    /* Sequences with multiple elements. A Fisher-Yates shuffle of a sequence S
     * is a random permutation \pi(S) of S. Thus \pi(S) must have the same
     * length and elements as the original sequence S. A major difference between
     * S and its random permutation \pi(S) is that the order in which elements
     * appear in \pi(S) is probably different from how elements are ordered in S.
     * If S has length n = 1, then both \pi(S) and S are equivalent sequences in
     * that \pi(S) is merely S and no permutation has taken place. If S has
     * length n > 1, then there are n! possible permutations of S. Assume that
     * each such permutation is equally likely to appear as a result of the
     * Fisher-Yates shuffle. As n increases, the probability that S is different
     * from \pi(S) also increases. We have a probability of 1 / n! that S and
     * \pi(S) are equivalent sequences.
     */
    n = 100;
    igraph_vector_init(&u, n);
    igraph_vector_init(&v, n);

    for (i = 0; i < n; i++) {
        k = R_INTEGER(-1000, 1000);
        VECTOR(u)[i] = k;
        VECTOR(v)[i] = k;
    }

    igraph_vector_shuffle(&v);
    /* must have same length */
    if (igraph_vector_size(&v) != n) {
        return 3;
    }
    if (igraph_vector_size(&u) != igraph_vector_size(&v)) {
        return 4;
    }
    /* must have same elements */
    igraph_vector_sort(&u);
    igraph_vector_sort(&v);
    if (!igraph_vector_all_e(&u, &v)) {
        return 5;
    }
    igraph_vector_destroy(&u);
    igraph_vector_destroy(&v);

    /* empty sequence */
    igraph_vector_init(&v, 0);
    igraph_vector_shuffle(&v);
    igraph_vector_destroy(&v);

    return 0;
}


2.7.6. igraph_vector_permute — 根据索引向量就地排列向量的元素。

igraph_error_t igraph_vector_permute(igraph_vector_t *v, const igraph_vector_int_t *index);

此函数采用向量 v 和相应的索引向量 ind,并排列 v 的元素,使得在函数执行后,v[ind[i]] 被移动为 v[i]。

使用不表示有效排列的索引向量调用此函数是错误的。索引向量中的每个元素必须介于 0 和向量长度减一之间(包括),并且每个这样的元素必须只出现一次。该函数不会尝试验证索引向量。

此函数采用的索引向量与从 igraph_vector_sort_ind() 返回的索引向量兼容;传入来自 igraph_vector_sort_ind() 的索引向量将对原始向量进行排序。

作为一种特殊情况,此函数允许索引向量比要排列的向量,在这种情况下,索引向量中未出现的索引的元素将从向量中删除。

参数: 

v:

要排列的向量

索引:

索引向量

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:O(n),向量的大小。

2.8. 向量运算

2.8.1. igraph_vector_add_constant — 将一个常量加到向量上。

void igraph_vector_add_constant(igraph_vector_t *v, igraph_real_t plus);

plus 被加到 v 的每个元素上。请注意,可能会发生溢出。

参数: 

v:

输入向量。

plus:

要添加的常量。

时间复杂度:O(n),元素数量。

2.8.2. igraph_vector_scale — 将向量的所有元素乘以一个常量。

void igraph_vector_scale(igraph_vector_t *v, igraph_real_t by);

参数: 

v:

向量。

by:

常量。

返回值: 

错误代码。当前实现始终返回成功。

在 0.2 版本中添加。

时间复杂度:O(n),向量中元素的数量。

2.8.3. igraph_vector_add — 将两个向量相加。

igraph_error_t igraph_vector_add(igraph_vector_t *v1,
                                 const igraph_vector_t *v2);

v2 的元素添加到 v1,结果存储在 v1 中。两个向量必须具有相同的长度。

参数: 

v1:

第一个向量,结果将存储在这里。

v2:

第二个向量,其内容将保持不变。

返回值: 

错误代码。

时间复杂度:O(n),元素数量。

2.8.4. igraph_vector_sub — 从一个向量中减去另一个向量。

igraph_error_t igraph_vector_sub(igraph_vector_t *v1,
                                 const igraph_vector_t *v2);

v1 中减去 v2 的元素,结果存储在 v1 中。两个向量必须具有相同的长度。

参数: 

v1:

第一个向量,从中减去。结果存储在这里。

v2:

要减去的向量,它将保持不变。

返回值: 

错误代码。

时间复杂度:O(n),向量的长度。

2.8.5. igraph_vector_mul — 将两个向量相乘。

igraph_error_t igraph_vector_mul(igraph_vector_t *v1,
                                 const igraph_vector_t *v2);

v1 将逐元素乘以 v2。两个向量必须具有相同的长度。

参数: 

v1:

第一个向量,结果将存储在这里。

v2:

第二个向量,它保持不变。

返回值: 

错误代码。

时间复杂度:O(n),元素数量。

2.8.6. igraph_vector_div — 将一个向量除以另一个向量。

igraph_error_t igraph_vector_div(igraph_vector_t *v1,
                                 const igraph_vector_t *v2);

v1 逐元素除以 v2。它们必须具有相同的长度。如果向量的基本类型可能产生除零错误,请确保 v2 不包含零,以避免问题。

参数: 

v1:

被除数。结果也存储在这里。

v2:

除数,它保持不变。

返回值: 

错误代码。

时间复杂度:O(n),向量的长度。

2.8.7. igraph_vector_floor — 通过对每个元素向下取整,将实数向量转换为整数向量。

igraph_error_t igraph_vector_floor(const igraph_vector_t *from, igraph_vector_int_t *to);

向下取整意味着四舍五入到最接近的整数。

参数: 

:

原始实数向量对象。

:

指向已初始化的整数向量的指针。结果将存储在这里。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足

时间复杂度:O(n),其中 n 是向量中元素的数量。

2.9. 向量比较

2.9.1. igraph_vector_all_e — 所有元素都相等吗?

igraph_bool_t igraph_vector_all_e(const igraph_vector_t *lhs,
                                  const igraph_vector_t *rhs);

检查两个向量的元素级相等性。对于包含浮点数值的向量,请考虑使用 igraph_matrix_all_almost_e()

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都等于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。

时间复杂度:O(n),向量的长度。

2.9.2. igraph_vector_all_almost_e — 所有元素都几乎相等吗?

igraph_bool_t igraph_vector_all_almost_e(const igraph_vector_t *lhs,
                                         const igraph_vector_t *rhs,
                                         igraph_real_t eps);

检查两个向量的元素是否在相对容差范围内相等。

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

eps:

相对容差,详见 igraph_almost_equals()

返回值: 

如果两个向量几乎相等则为真,如果至少有一个不同的元素或向量的大小不相同则为假。

2.9.3. igraph_vector_all_l — 所有元素都小于吗?

igraph_bool_t igraph_vector_all_l(const igraph_vector_t *lhs,
                                  const igraph_vector_t *rhs);

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都小于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。如果有任何元素是 NaN,它将返回 false。

时间复杂度:O(n),向量的长度。

2.9.4. igraph_vector_all_g — 所有元素都大于吗?

igraph_bool_t igraph_vector_all_g(const igraph_vector_t *lhs,
                                  const igraph_vector_t *rhs);

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都大于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。如果有任何元素是 NaN,它将返回 false。

时间复杂度:O(n),向量的长度。

2.9.5. igraph_vector_all_le — 所有元素都小于或等于吗?

igraph_bool_t igraph_vector_all_le(const igraph_vector_t *lhs,
                                   const igraph_vector_t *rhs);

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都小于或等于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。如果有任何元素是 NaN,它将返回 false。

时间复杂度:O(n),向量的长度。

2.9.6. igraph_vector_all_ge — 所有元素都大于或等于吗?

igraph_bool_t igraph_vector_all_ge(const igraph_vector_t *lhs,
                                   const igraph_vector_t *rhs);

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都大于或等于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。如果有任何元素是 NaN,它将返回 false。

时间复杂度:O(n),向量的长度。

2.9.7. igraph_vector_is_equal — 所有元素都相等吗?

igraph_bool_t igraph_vector_is_equal(const igraph_vector_t *lhs,
                                     const igraph_vector_t *rhs);

这是 igraph_vector_all_e() 的别名,名称更直观。

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

返回值: 

如果 lhs 中的元素都等于 rhs 中的对应元素,则为真。如果向量的长度不匹配,则返回 false。

时间复杂度:O(n),向量的长度。

2.9.8. igraph_vector_zapsmall — 将向量中的小元素替换为精确的零。

igraph_error_t igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol);

幅度小于给定绝对容差的向量元素将被替换为精确的零。默认容差对应于 igraph_real_t 的可表示数字的三分之二,即 DBL_EPSILON^(2/3),大约为 10^-10

参数: 

v:

要处理的向量,它将被就地更改。

tol:

容差值。幅度小于此值的数字将被替换为零。传入零以使用默认容差。不能为负数。

返回值: 

错误代码。

另请参阅: 

igraph_vector_all_almost_e()igraph_almost_equals() 来执行具有相对容差的比较。

2.9.9. igraph_vector_lex_cmp — 两个向量的字典序比较(类型安全变体)。

int igraph_vector_lex_cmp(
    const igraph_vector_t *lhs, const igraph_vector_t *rhs
);

如果两个向量的元素匹配但一个较短,则较短的向量排在前面。因此 {1, 3} 排在 {1, 2, 3} 之后,但在 {1, 3, 4} 之前。

此函数通常与 igraph_vector_list_sort() 一起使用。

参数: 

lhs:

指向第一个向量的指针。

rhs:

指向第二个向量的指针。

返回值: 

如果 lhs 在字典序上较小则为 -1,如果 lhsrhs 相等则为 0,否则为 1。

另请参阅: 

有关此函数的非类型化变体,请参阅 igraph_vector_lex_cmp_untyped(),有关从最后一个元素开始比较向量,请参阅 igraph_vector_colex_cmp()

时间复杂度:O(n),较小向量中元素的数量。

示例 7.2.  文件 examples/simple/igraph_vector_int_list_sort.c

#include <igraph.h>
#include <stdio.h>

int main(void) {
    igraph_t graph;
    igraph_vector_int_list_t cliques;
    igraph_integer_t i, n;

    /* Set a random seed to make the program deterministic */
    igraph_rng_seed(igraph_rng_default(), 31415);

    /* Create a random graph with a given number of vertices and edges */
    igraph_erdos_renyi_game_gnm(&graph, 15, 80, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);

    /* Find all maximal cliques in the graph */
    igraph_vector_int_list_init(&cliques, 0);
    igraph_maximal_cliques(&graph, &cliques, -1, -1);

    /* Print the cliques in lexicographical order */
    printf("Maximal cliques in lexicographical order:\n");
    igraph_vector_int_list_sort(&cliques, igraph_vector_int_lex_cmp);
    n = igraph_vector_int_list_size(&cliques);
    for (i=0; i < n; ++i) {
        igraph_vector_int_print(igraph_vector_int_list_get_ptr(&cliques, i));
    }

    /* Print the cliques in colexicographical order */
    printf("\nMaximal cliques in colexicographical order:\n");
    igraph_vector_int_list_sort(&cliques, igraph_vector_int_colex_cmp);
    n = igraph_vector_int_list_size(&cliques);
    for (i=0; i < n; ++i) {
        igraph_vector_int_print(igraph_vector_int_list_get_ptr(&cliques, i));
    }

    /* Destroy data structures when we no longer need them */
    igraph_vector_int_list_destroy(&cliques);
    igraph_destroy(&graph);

    return 0;
}


2.9.10. igraph_vector_lex_cmp_untyped — 两个向量的字典序比较(非类型安全)。

int igraph_vector_lex_cmp_untyped(const void *lhs, const void *rhs);

如果两个向量的元素匹配但一个较短,则较短的向量排在前面。因此 {1, 3} 排在 {1, 2, 3} 之后,但在 {1, 3, 4} 之前。

此函数通常与 igraph_vector_ptr_sort() 一起使用。

参数: 

lhs:

指向指向第一个向量的指针的指针(解释为 igraph_vector_t **)。

rhs:

指向指向第二个向量的指针的指针(解释为 igraph_vector_t **)。

返回值: 

如果 lhs 在字典序上较小则为 -1,如果 lhsrhs 相等则为 0,否则为 1。

另请参阅: 

有关此函数的类型安全变体,请参阅 igraph_vector_lex_cmp(),有关从最后一个元素开始比较向量,请参阅 igraph_vector_colex_cmp_untyped()

时间复杂度:O(n),较小向量中元素的数量。

2.9.11. igraph_vector_colex_cmp — 两个向量的逆字典序比较。

int igraph_vector_colex_cmp(
    const igraph_vector_t *lhs, const igraph_vector_t *rhs
);

此比较从两个向量的最后一个元素开始并向后移动。如果两个向量的元素匹配但一个较短,则较短的向量排在前面。因此 {1, 2} 排在 {3, 2, 1} 之后,但在 {0, 1, 2} 之前。

此函数通常与 igraph_vector_list_sort() 一起使用。

参数: 

lhs:

指向指向第一个向量的指针的指针。

rhs:

指向指向第二个向量的指针的指针。

返回值: 

如果 lhs 的反向顺序在字典序上小于 rhs 的反向顺序则为 -1,如果 lhsrhs 相等则为 0,否则为 1。

另请参阅: 

有关此函数的非类型化变体,请参阅 igraph_vector_colex_cmp_untyped(),有关从第一个元素开始比较向量,请参阅 igraph_vector_lex_cmp()

时间复杂度:O(n),较小向量中元素的数量。

示例 7.3.  文件 examples/simple/igraph_vector_int_list_sort.c

#include <igraph.h>
#include <stdio.h>

int main(void) {
    igraph_t graph;
    igraph_vector_int_list_t cliques;
    igraph_integer_t i, n;

    /* Set a random seed to make the program deterministic */
    igraph_rng_seed(igraph_rng_default(), 31415);

    /* Create a random graph with a given number of vertices and edges */
    igraph_erdos_renyi_game_gnm(&graph, 15, 80, IGRAPH_UNDIRECTED, IGRAPH_NO_LOOPS);

    /* Find all maximal cliques in the graph */
    igraph_vector_int_list_init(&cliques, 0);
    igraph_maximal_cliques(&graph, &cliques, -1, -1);

    /* Print the cliques in lexicographical order */
    printf("Maximal cliques in lexicographical order:\n");
    igraph_vector_int_list_sort(&cliques, igraph_vector_int_lex_cmp);
    n = igraph_vector_int_list_size(&cliques);
    for (i=0; i < n; ++i) {
        igraph_vector_int_print(igraph_vector_int_list_get_ptr(&cliques, i));
    }

    /* Print the cliques in colexicographical order */
    printf("\nMaximal cliques in colexicographical order:\n");
    igraph_vector_int_list_sort(&cliques, igraph_vector_int_colex_cmp);
    n = igraph_vector_int_list_size(&cliques);
    for (i=0; i < n; ++i) {
        igraph_vector_int_print(igraph_vector_int_list_get_ptr(&cliques, i));
    }

    /* Destroy data structures when we no longer need them */
    igraph_vector_int_list_destroy(&cliques);
    igraph_destroy(&graph);

    return 0;
}


2.9.12. igraph_vector_colex_cmp_untyped — 两个向量的逆字典序比较。

int igraph_vector_colex_cmp_untyped(const void *lhs, const void *rhs);

此比较从两个向量的最后一个元素开始并向后移动。如果两个向量的元素匹配但一个较短,则较短的向量排在前面。因此 {1, 2} 排在 {3, 2, 1} 之后,但在 {0, 1, 2} 之前。

此函数通常与 igraph_vector_ptr_sort() 一起使用。

参数: 

lhs:

指向指向第一个向量的指针的指针(解释为 igraph_vector_t **)。

rhs:

指向指向第二个向量的指针的指针(解释为 igraph_vector_t **)。

返回值: 

如果 lhs 的反向顺序在字典序上小于 rhs 的反向顺序则为 -1,如果 lhsrhs 相等则为 0,否则为 1。

另请参阅: 

有关此函数的类型安全变体,请参阅 igraph_vector_colex_cmp(),有关从第一个元素开始比较向量,请参阅 igraph_vector_lex_cmp_untyped()

时间复杂度:O(n),较小向量中元素的数量。

2.10. 查找最小值和最大值

2.10.1. igraph_vector_min — 向量的最小元素。

igraph_real_t igraph_vector_min(const igraph_vector_t *v);

向量不能为空。

参数: 

v:

输入向量。

返回值: 

v 的最小元素,或者如果任何元素是 NaN,则为 NaN。

时间复杂度:O(n),元素数量。

2.10.2. igraph_vector_max — 向量的最大元素。

igraph_real_t igraph_vector_max(const igraph_vector_t *v);

向量不能为空。

参数: 

v:

向量对象。

返回值: 

v 的最大元素,或者如果任何元素是 NaN,则为 NaN。

时间复杂度:O(n),元素数量。

2.10.3. igraph_vector_which_min — 最小元素的索引。

igraph_integer_t igraph_vector_which_min(const igraph_vector_t* v);

向量不能为空。如果最小元素不是唯一的,则返回第一个的索引。如果向量包含 NaN 值,则返回第一个 NaN 值的索引。

参数: 

v:

输入向量。

返回值: 

最小元素的索引。

时间复杂度:O(n),元素数量。

2.10.4. igraph_vector_which_max — 给出向量最大元素的索引。

igraph_integer_t igraph_vector_which_max(const igraph_vector_t *v);

向量不能为空。如果最大元素不是唯一的,则返回第一个的索引。如果向量包含 NaN 值,则返回第一个 NaN 值的索引。

参数: 

v:

向量对象。

返回值: 

第一个最大元素的索引。

时间复杂度:O(n),n 是向量的大小。

2.10.5. igraph_vector_minmax — 向量的最小和最大元素。

void igraph_vector_minmax(const igraph_vector_t *v,
                          igraph_real_t *min, igraph_real_t *max);

如果您想要向量的最小和最大元素,则很方便。向量仅被遍历一次。向量必须非空。如果向量包含至少一个 NaN,则 minmax 都将是 NaN。

参数: 

v:

输入向量。它必须包含至少一个元素。

min:

指向基本类型变量的指针,最小值存储在这里。

max:

指向基本类型变量的指针,最大值存储在这里。

时间复杂度:O(n),元素数量。

2.10.6. igraph_vector_which_minmax — 最小和最大元素的索引。

void igraph_vector_which_minmax(const igraph_vector_t *v,
        igraph_integer_t *which_min, igraph_integer_t *which_max);

如果您需要最小和最大元素的索引,则很方便。向量仅被遍历一次。向量必须非空。如果最小值或最大值不是唯一的,则分别返回第一个最小值或第一个最大值的索引。如果向量包含至少一个 NaN,则 which_minwhich_max 都将指向第一个 NaN 值。

参数: 

v:

输入向量。它必须包含至少一个元素。

which_min:

最小元素的索引将存储在这里。

which_max:

最大元素的索引将存储在这里。

时间复杂度:O(n),元素数量。

2.11. 向量属性

2.11.1. igraph_vector_empty — 确定向量的大小是否为零。

igraph_bool_t igraph_vector_empty(const igraph_vector_t *v);

参数: 

v:

向量对象。

返回值: 

如果向量的大小为零则为真,否则为假。

时间复杂度:O(1)。

2.11.2. igraph_vector_size — 向量的大小。

igraph_integer_t igraph_vector_size(const igraph_vector_t *v);

返回向量中存储的元素数。

参数: 

v:

向量对象

返回值: 

向量的大小。

时间复杂度:O(1)。

2.11.3. igraph_vector_capacity — 返回向量的已分配容量。

igraph_integer_t igraph_vector_capacity(const igraph_vector_t *v);

请注意,这可能与向量的大小(由 igraph_vector_size() 查询)不同,并且指定向量可以容纳多少个元素,而无需重新分配。

参数: 

v:

指向(先前初始化的)要查询的向量对象的指针。

返回值: 

已分配容量。

另请参阅: 

时间复杂度:O(1)。

2.11.4. igraph_vector_sum — 计算向量中元素的总和。

igraph_real_t igraph_vector_sum(const igraph_vector_t *v);

对于空向量,返回 0。

参数: 

v:

向量对象。

返回值: 

元素的总和。

时间复杂度:O(n),向量的大小。

2.11.5. igraph_vector_prod — 计算向量中元素的乘积。

igraph_real_t igraph_vector_prod(const igraph_vector_t *v);

对于空向量,返回 1。

参数: 

v:

向量对象。

返回值: 

元素的乘积。

时间复杂度:O(n),向量的大小。

2.11.6. igraph_vector_isininterval — 检查向量的所有元素是否都在给定的间隔内。

igraph_bool_t igraph_vector_isininterval(const igraph_vector_t *v,
        igraph_real_t low,
        igraph_real_t high);

参数: 

v:

向量对象。

low:

间隔的下限(包括)。

high:

间隔的上限(包括)。

返回值: 

如果向量为空或所有向量元素都在间隔内,则为真,否则为假。如果有任何元素是 NaN,它将返回 false。

时间复杂度:O(n),向量中的元素数量。

2.11.7. igraph_vector_maxdifferencem1m2 的最大绝对差。

igraph_real_t igraph_vector_maxdifference(const igraph_vector_t *m1,
        const igraph_vector_t *m2);

返回 m1 - m2 中具有最大绝对值的元素。两个向量必须非空,但它们不需要具有相同的长度,较长向量中的额外元素将被忽略。如果较短向量中有任何值是 NaN,则结果将是 NaN。

参数: 

m1:

第一个向量。

m2:

第二个向量。

返回值: 

m1m2 的最大绝对差。

时间复杂度:O(n),较短向量中元素的数量。

2.11.8. igraph_vector_is_nan — 检查每个元素是否为 NaN。

igraph_error_t igraph_vector_is_nan(const igraph_vector_t *v, igraph_vector_bool_t *is_nan);

参数: 

v:

要检查的 igraph_vector_t 对象。

is_nan:

结果布尔向量,指示每个元素是否为 NaN。

返回值: 

错误代码,IGRAPH_ENOMEM 如果没有足够的内存。请注意,如果向量 is_nan 已经足够大,则此函数永远不会返回错误。

时间复杂度:O(n),元素数量。

2.11.9. igraph_vector_is_any_nan — 检查是否有任何元素是 NaN。

igraph_bool_t igraph_vector_is_any_nan(const igraph_vector_t *v);

参数: 

v:

要检查的 igraph_vector_t 对象。

返回值: 

如果有任何元素是 NaN,则为真,否则为假。

时间复杂度:O(n),元素数量。

2.11.10. igraph_vector_is_all_finite — 检查所有元素是否都是有限的。

igraph_bool_t igraph_vector_is_all_finite(const igraph_vector_t *v);

参数: 

v:

要检查的 igraph_vector_t 对象。

返回值: 

如果所有元素都不是无穷大或 NaN,则为真。

时间复杂度:O(n),元素数量。

2.12. 搜索元素

2.12.1. igraph_vector_contains — 在向量中线性搜索。

igraph_bool_t igraph_vector_contains(const igraph_vector_t *v,
        igraph_real_t what);

通过线性搜索检查提供的元素是否包含在向量中。

参数: 

v:

输入向量。

what:

要查找的元素。

返回值: 

如果找到该元素则为 true,否则为 false

时间复杂度:O(n),向量的长度。

2.12.2. igraph_vector_search — 从给定位置在向量中搜索。

igraph_bool_t igraph_vector_search(const igraph_vector_t *v,
        igraph_integer_t from, igraph_real_t what, igraph_integer_t *pos);

提供的元素 what 在向量 v 中搜索,从元素索引 from 开始。如果找到,则第一个实例的索引(在 from 之后)存储在 pos 中。

参数: 

v:

输入向量。

:

开始搜索的索引。不执行范围检查。

what:

要查找的元素。

位置:

如果不是 NULL,则找到的元素的索引存储在这里。

返回值: 

布尔值,如果找到该元素则为 true,否则为 false

时间复杂度:O(m),要搜索的元素数,向量的长度减去 from 参数。

2.12.3. igraph_vector_binsearch — 通过对排序向量进行二分搜索来查找元素。

igraph_bool_t igraph_vector_binsearch(const igraph_vector_t *v,
        igraph_real_t what, igraph_integer_t *pos);

假设向量已排序。如果指定的元素 (what) 不在向量中,则返回应插入该元素的位置(以保持向量排序)。如果向量包含任何 NaN 值,则返回的值是未定义的,并且 pos 可能指向任何位置。

参数: 

v:

igraph_vector_t 对象。

what:

要搜索的元素。

位置:

指向 igraph_integer_t 的指针。如果向量中存在 what 的实例,则将其设置为该实例的位置。如果 v 不包含 what,则 pos 设置为应插入该元素的位置(当然,为了保持向量排序)。

返回值: 

如果向量中找到 what,则为真,否则为假。

时间复杂度:O(log(n)),n 是 v 中的元素数。

2.12.4. igraph_vector_binsearch_slice — 通过对排序向量的切片进行二分搜索来查找元素。

igraph_bool_t igraph_vector_binsearch_slice(const igraph_vector_t *v,
        igraph_real_t what, igraph_integer_t *pos, igraph_integer_t start, igraph_integer_t end);

假设向量的指示切片(从 startend)已排序。如果指定的元素 (what) 不在向量的切片中,则返回应插入该元素的位置(以保持 切片 排序)。请注意,这意味着返回的索引将指向切片的 内部(包括其端点),但不会计算切片外部的值。如果指示的切片包含任何 NaN 值,则返回的值是未定义的,并且 pos 可能指向切片中的任何位置。

参数: 

v:

igraph_vector_t 对象。

what:

要搜索的元素。

位置:

指向 igraph_integer_t 的指针。如果向量的切片中存在 what 的实例,则将其设置为该实例的位置。如果 v 不包含 what,则 pos 设置为应插入该元素的位置(为了保持向量排序)。

开始:

要搜索的切片的起始位置(包括)。

结束:

要搜索的切片的结束位置(不包括)。

返回值: 

如果向量中找到 what,则为真,否则为假。

时间复杂度:O(log(n)),n 是 v 切片中的元素数,即 end - start

2.12.5. igraph_vector_contains_sorted — 在排序向量中进行二分搜索。

igraph_bool_t igraph_vector_contains_sorted(const igraph_vector_t *v, igraph_real_t what);

假设向量已排序。

参数: 

v:

igraph_vector_t 对象。

what:

要搜索的元素。

返回值: 

如果向量中找到 what,则为真,否则为假。

时间复杂度:O(log(n)),n 是 v 中的元素数。

2.13. 调整大小操作

2.13.1. igraph_vector_clear — 从向量中删除所有元素。

void igraph_vector_clear(igraph_vector_t* v);

此函数只是将向量的大小设置为零,它不会释放任何已分配的内存。为此,您必须调用 igraph_vector_destroy()

参数: 

v:

向量对象。

时间复杂度:O(1)。

2.13.2. igraph_vector_reserve — 为向量预留内存。

igraph_error_t igraph_vector_reserve(igraph_vector_t *v, igraph_integer_t capacity);

igraph 向量是灵活的,它们可以增长和收缩。但是,增长有时需要复制向量中的数据。为了避免这种情况,您可以调用此函数来为向量的未来增长预留空间。

请注意,此函数更改向量的大小。让我们看一个小例子来澄清一下:如果您为 100 个元素预留空间,并且向量的大小是(并且仍然是)60,那么您肯定可以在复制向量之前向向量添加额外的 40 个元素。

参数: 

v:

向量对象。

capacity:

向量的新已分配大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:依赖于操作系统,应该在 O(n) 左右,n 是向量的新已分配大小。

2.13.3. igraph_vector_resize — 调整向量大小。

igraph_error_t igraph_vector_resize(igraph_vector_t* v, igraph_integer_t new_size);

请注意,此函数不会释放任何内存,只是将向量的大小设置为给定的大小。另一方面,如果新大小大于先前的大小,它可以分配更多内存。在这种情况下,向量中新出现的元素设置为零,它们是未初始化的。

参数: 

v:

向量对象

new_size:

向量的新大小。

返回值: 

错误代码,IGRAPH_ENOMEM 如果没有足够的内存。请注意,如果向量变小,则此函数永远不会返回错误。

另请参阅: 

有关为向量的未来扩展分配内存的信息,请参见 igraph_vector_reserve()。有关释放向量的不必要内存,请参见 igraph_vector_resize_min()

时间复杂度:如果新大小较小,则为 O(1),如果较大,则依赖于操作系统。在后一种情况下,通常约为 O(n),n 是向量的新大小。

2.13.4. igraph_vector_resize_min — 释放向量的未使用内存。

void igraph_vector_resize_min(igraph_vector_t *v);

此函数尝试释放向量的未使用预留存储空间。如果成功,igraph_vector_size()igraph_vector_capacity() 将相同。向量中的数据始终被保留,即使释放不成功。

参数: 

v:

指向已初始化向量的指针。

另请参阅: 

时间复杂度:依赖于操作系统,最坏情况下为 O(n)。

2.13.5. igraph_vector_push_back — 将一个元素追加到向量。

igraph_error_t igraph_vector_push_back(igraph_vector_t *v, igraph_real_t e);

此函数将向量的大小调整为比原来长一个元素,并将向量中的最后一个元素设置为 e

参数: 

v:

向量对象。

e:

要追加到向量的元素。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:依赖于操作系统。重要的是,对该函数的 n 次后续调用的时间复杂度为 O(n),即使 igraph_vector_reserve() 没有为新元素预留任何空间。这是通过类似于 C++ vector 类的技巧实现的:每次为向量分配更多内存时,额外分配的内存大小与向量的当前长度相同。(我们在这里假设内存分配的时间复杂度最多是线性的。)

2.13.6. igraph_vector_pop_back — 删除并返回向量的最后一个元素。

igraph_real_t igraph_vector_pop_back(igraph_vector_t *v);

使用空向量调用此函数是一个错误。

参数: 

v:

向量对象。

返回值: 

删除的最后一个元素。

时间复杂度:O(1)。

2.13.7. igraph_vector_insert — 将单个元素插入向量。

igraph_error_t igraph_vector_insert(
        igraph_vector_t *v, igraph_integer_t pos, igraph_real_t value);

请注意,此函数不进行范围检查。插入会将元素从给定位置到向量末尾向右移动一个位置,并将新元素插入到给定位置创建的空白空间中。向量的大小将增加 1。

参数: 

v:

向量对象。

位置:

要在其中插入新元素的位置。

:

要插入的新元素。

2.13.8. igraph_vector_remove — 从向量中删除单个元素。

void igraph_vector_remove(igraph_vector_t *v, igraph_integer_t elem);

请注意,此函数不进行范围检查。

参数: 

v:

向量对象。

elem:

要删除的元素的位置。

时间复杂度:O(n-elem),n 是向量中元素的数量。

2.13.9. igraph_vector_remove_section — 从向量中删除一个部分。

void igraph_vector_remove_section(
        igraph_vector_t *v, igraph_integer_t from, igraph_integer_t to);

参数: 

v:

向量对象。

:

要删除的第一个元素的位置。

:

第一个要删除的元素的位置。

时间复杂度:O(n-from),n 是向量中元素的数量。

2.14. 复数向量运算

2.14.1. igraph_vector_complex_real — 返回复向量的实部。

igraph_error_t igraph_vector_complex_real(const igraph_vector_complex_t *v,
                               igraph_vector_t *real);

参数: 

v:

指向复向量的指针。

实部:

指向已初始化的向量的指针。结果将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),向量中的元素数量。

2.14.2. igraph_vector_complex_imag — 返回复向量的虚部。

igraph_error_t igraph_vector_complex_imag(const igraph_vector_complex_t *v,
                               igraph_vector_t *imag);

参数: 

v:

指向复向量的指针。

实部:

指向已初始化的向量的指针。结果将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),向量中的元素数量。

2.14.3. igraph_vector_complex_realimag — 返回复向量的实部和虚部。

igraph_error_t igraph_vector_complex_realimag(const igraph_vector_complex_t *v,
                                   igraph_vector_t *real,
                                   igraph_vector_t *imag);

参数: 

v:

指向复向量的指针。

实部:

指向已初始化的向量的指针。实部将存储在此处。

虚部:

指向已初始化的向量的指针。虚部将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),向量中的元素数量。

2.14.4. igraph_vector_complex_create — 从实部和虚部创建一个复向量。

igraph_error_t igraph_vector_complex_create(igraph_vector_complex_t *v,
                                 const igraph_vector_t *real,
                                 const igraph_vector_t *imag);

参数: 

v:

指向未初始化的复向量的指针。

实部:

指向复向量实部的指针。

虚部:

指向复向量虚部的指针。

返回值: 

错误代码。

时间复杂度:O(n),向量中的元素数量。

2.14.5. igraph_vector_complex_create_polar — 从幅值和角度创建一个复矩阵。

igraph_error_t igraph_vector_complex_create_polar(igraph_vector_complex_t *v,
                                       const igraph_vector_t *r,
                                       const igraph_vector_t *theta);

参数: 

m:

指向未初始化的复向量的指针。

r:

指向包含幅值的实向量的指针。

theta:

指向包含辐角(相位角)的实向量的指针。

返回值: 

错误代码。

时间复杂度:O(n),向量中的元素数量。

2.14.6. igraph_vector_complex_all_almost_e — 所有元素是否几乎相等?

igraph_bool_t igraph_vector_complex_all_almost_e(const igraph_vector_complex_t *lhs,
                                                 const igraph_vector_complex_t *rhs,
                                                 igraph_real_t eps);

检查两个复向量的元素是否在相对容差范围内相等。

参数: 

lhs:

第一个向量。

rhs:

第二个向量。

eps:

相对容差,有关详细信息,请参见 igraph_complex_almost_equals()

返回值: 

如果两个向量几乎相等则为真,如果至少有一个不同的元素或向量的大小不相同则为假。

2.14.7. igraph_vector_complex_zapsmall — 将复向量中的小元素替换为精确的零。

igraph_error_t igraph_vector_complex_zapsmall(igraph_vector_complex_t *v, igraph_real_t tol);

igraph_vector_zapsmall() 类似,小元素将被替换为零。该操作分别对数字的实部和虚部执行。这样,具有大实部和小虚部的复数将被有效地转换为实数。默认容差对应于 igraph_real_t 的可表示位数的⅔,即 DBL_EPSILON^(2/3),大约为 10^-10

参数: 

v:

要处理的向量,它将被就地更改。

tol:

容差值。实部和虚部小于此幅度的部分将被替换为零。传入零以使用默认容差。不能为负。

返回值: 

错误代码。

另请参阅: 

使用 igraph_vector_complex_all_almost_e()igraph_complex_almost_equals() 执行具有相对容差的比较。

2.15. 排序

2.15.1. igraph_vector_sort — 将向量的元素排序为升序。

void igraph_vector_sort(igraph_vector_t *v);

如果向量包含任何 NaN 值,则 NaN 值的最终排序是未定义的,并且可能出现在向量中的任何位置。

参数: 

v:

指向已初始化的向量对象的指针。

时间复杂度:对于 n 个元素为 O(n log n)。

2.15.2. igraph_vector_reverse_sort — 将向量的元素排序为降序。

void igraph_vector_reverse_sort(igraph_vector_t *v);

如果向量包含任何 NaN 值,则 NaN 值的最终排序是未定义的,并且可能出现在向量中的任何位置。

参数: 

v:

指向已初始化的向量对象的指针。

时间复杂度:对于 n 个元素为 O(n log n)。

2.15.3. igraph_vector_sort_ind — 返回对向量进行排序的索引置换。

igraph_error_t igraph_vector_sort_ind(
        const igraph_vector_t *v,
        igraph_vector_int_t *inds,
        igraph_order_t order);

接受一个未排序的数组 v 作为输入,并计算一个索引数组 inds,使得 v[ inds[i] ],其中 i 从 0 开始递增,是一个有序数组(升序或降序,具体取决于 order)。相同元素的索引顺序未定义。如果向量包含任何 NaN 值,则 NaN 值的排序是未定义的。

参数: 

v:

要排序的数组

inds:

索引的输出数组。必须初始化,但将调整大小

order:

输出数组应按升序还是降序排序。使用 IGRAPH_ASCENDING 表示升序,使用 IGRAPH_DESCENDING 表示降序。

返回值: 

错误代码。

此例程使用 igraph 的内置 qsort 例程。算法:1) 创建一个指向 v 元素的指针数组。2) 将此数组传递给 qsort。3) 排序后,指针值与第一个指针值之间的差异给出了其在数组中的原始位置。使用此来设置 inds 的值。

2.16. 对排序向量执行集合运算

2.16.1. igraph_vector_intersect_sorted — 两个排序向量的集合交集。

igraph_error_t igraph_vector_intersect_sorted(const igraph_vector_t *v1,
        const igraph_vector_t *v2, igraph_vector_t *result);

同时包含在两个向量中的元素存储在结果向量中。所有三个向量都必须初始化。

对于大小相似的向量,此函数使用简单的线性扫描。当向量大小差异很大时,它使用 Ricardo Baeza-Yates 的集合交集方法,该方法在较大向量的长度中花费对数时间。

该算法保留元素的重数:如果一个元素在第一个向量中出现 k1 次,在第二个向量中出现 k2 次,则结果将包括该元素 min(k1, k2) 次。

参考

Baeza-Yates R: A fast set intersection algorithm for sorted sequences. In: Lecture Notes in Computer Science, vol. 3109/2004, pp. 400--408, 2004. Springer Berlin/Heidelberg. https://doi.org/10.1007/978-3-540-27801-6_30

参数: 

v1:

第一个向量

v2:

第二个向量

结果:

结果向量,也将被排序。

返回值: 

错误代码。

时间复杂度:O(m log(n)),其中 m 是较小向量的大小,n 是较大向量的大小。

2.16.2. igraph_vector_intersection_size_sorted — 两个排序向量的交集大小。

igraph_integer_t igraph_vector_intersection_size_sorted(
        const igraph_vector_t *v1,
        const igraph_vector_t *v2);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

计算两个向量中都存在的元素。这对于计算两个顶点的共同邻居特别有用。

对于大小相似的向量,此函数使用简单的线性扫描。当向量大小差异很大时,它使用 Ricardo Baeza-Yates 的集合交集方法,该方法在较大向量的长度中花费对数时间。

该算法保留元素的重数:如果一个元素在第一个向量中出现 k1 次,在第二个向量中出现 k2 次,则结果将包括该元素 min(k1, k2) 次。

参考

Baeza-Yates R: A fast set intersection algorithm for sorted sequences. In: Lecture Notes in Computer Science, vol. 3109/2004, pp. 400--408, 2004. Springer Berlin/Heidelberg. https://doi.org/10.1007/978-3-540-27801-6_30

参数: 

v1:

第一个向量

v2:

第二个向量

返回值: 

公共元素的数量。

时间复杂度:O(m log(n)),其中 m 是较小向量的大小,n 是较大向量的大小。

2.16.3. igraph_vector_difference_sorted — 两个排序向量的集合差集。

igraph_error_t igraph_vector_difference_sorted(const igraph_vector_t *v1,
        const igraph_vector_t *v2, igraph_vector_t *result);

仅包含在第一个向量中但不包含在第二个向量中的元素存储在结果向量中。所有三个向量都必须初始化。

参数: 

v1:

第一个向量

v2:

第二个向量

结果:

结果向量

2.17. 指针向量 (igraph_vector_ptr_t)

2.17.1. igraph_vector_ptr_init — 初始化指针向量(构造函数)。
2.17.2. igraph_vector_ptr_init_copy — 从另一个指针向量初始化一个指针向量(构造函数)。
2.17.3. igraph_vector_ptr_destroy — 销毁指针向量。
2.17.4. igraph_vector_ptr_free_all — 释放指针向量的所有元素。
2.17.5. igraph_vector_ptr_destroy_all — 释放所有元素并销毁指针向量。
2.17.6. igraph_vector_ptr_size — 返回指针向量中的元素数量。
2.17.7. igraph_vector_ptr_clear — 从指针向量中删除所有元素。
2.17.8. igraph_vector_ptr_push_back — 将一个元素追加到指针向量的末尾。
2.17.9. igraph_vector_ptr_pop_back — 删除并返回指针向量的最后一个元素。
2.17.10. igraph_vector_ptr_insert — 将单个元素插入到指针向量中。
2.17.11. igraph_vector_ptr_get — 访问指针向量的元素。
2.17.12. igraph_vector_ptr_set — 分配给指针向量的元素。
2.17.13. igraph_vector_ptr_resize — 调整指针向量的大小。
2.17.14. igraph_vector_ptr_sort — 基于外部比较函数对指针向量进行排序。
2.17.15. igraph_vector_ptr_sort_ind — 返回对指针向量进行排序的索引置换。
2.17.16. igraph_vector_ptr_permute — 根据索引向量就地置换指针向量的元素。
2.17.17. igraph_vector_ptr_get_item_destructor — 获取此指针向量的当前项析构函数。
2.17.18. igraph_vector_ptr_set_item_destructor — 设置此指针向量的项析构函数。
2.17.19. IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR — 设置此指针向量的项析构函数(宏版本)。

igraph_vector_ptr_t 数据类型与 igraph_vector_t 类型非常相似,但它存储的是通用指针而不是实数。

此类型具有与 igraph_vector_t 相同的空间复杂度,并且大多数已实现的操作的工作方式与 igraph_vector_t 相同。

用于普通向量的相同 VECTOR 宏也可以用于指针向量,请注意,此宏将提供无类型通用指针,并且您可能需要在开始使用它之前将其强制转换为特定指针。

指针向量可能具有关联的项析构函数,该函数接受一个指针并且不返回任何内容。当通过 igraph_vector_ptr_destroy()igraph_vector_ptr_destroy_all() 销毁指针向量时,或者当 igraph_vector_ptr_free_all() 释放其元素时,将对指针向量中的每个项调用项析构函数。请注意,项析构函数的语义与 C++ 析构函数不一致;例如,当将指针向量调整为更小的大小时,额外的项将不会自动销毁!尽管如此,项析构函数在许多情况下可能会变得方便;例如,可以使用对 igraph_vector_ptr_destroy_all() 的单个调用来销毁由某些函数生成的图的向量(如果项析构函数设置为 igraph_destroy())。

2.17.1. igraph_vector_ptr_init — 初始化指针向量(构造函数)。

igraph_error_t igraph_vector_ptr_init(igraph_vector_ptr_t* v, igraph_integer_t size);

这是指针向量数据类型的构造函数。以这种方式构造的所有指针向量都应通过调用 igraph_vector_ptr_destroy() 来销毁。

参数: 

v:

指向未初始化的 igraph_vector_ptr_t 对象的指针,要创建。

大小:

整数,指针向量的大小。

返回值: 

错误代码:如果内存不足,则为 IGRAPH_ENOMEM

时间复杂度:操作系统依赖,分配 size 元素所需的时间量。

2.17.2. igraph_vector_ptr_init_copy — 从另一个指针向量初始化一个指针向量(构造函数)。

igraph_error_t igraph_vector_ptr_init_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from);

此函数通过复制另一个指针向量来创建一个指针向量。这是一个浅拷贝,只会复制向量中的指针。

复制具有关联的项析构函数的指针向量可能存在潜在的危险。复制的向量将继承项析构函数,这可能会在两个向量都被销毁时导致问题,因为这些项可能会被销毁两次。请确保您知道在复制具有项析构函数的指针向量时您在做什么,或者稍后取消设置其中一个向量的项析构函数。

参数: 

:

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

:

一个指针向量对象。

返回值: 

错误代码:如果内存不足,则为 IGRAPH_ENOMEM

时间复杂度:如果为 n 个元素分配内存可以在 O(n) 时间内完成,则为 O(n)。

2.17.3. igraph_vector_ptr_destroy — 销毁指针向量。

void igraph_vector_ptr_destroy(igraph_vector_ptr_t* v);

指针向量的析构函数。

参数: 

v:

指向要销毁的指针向量的指针。

时间复杂度:操作系统依赖,需要释放 O(n) 字节的时间,n 是为指针向量分配的元素数量(不一定是向量中的元素数量)。

2.17.4. igraph_vector_ptr_free_all — 释放指针向量的所有元素。

void igraph_vector_ptr_free_all(igraph_vector_ptr_t* v);

如果为此指针向量设置了项析构函数,则此函数将首先对向量的所有元素调用析构函数,然后使用 igraph_free() 释放所有元素。如果未设置项析构函数,则只会释放元素。

参数: 

v:

指向要释放其元素的指针向量的指针。

时间复杂度:操作系统依赖,调用析构函数 n 次然后释放 O(n) 个指针所需的时间,每个指针都指向任意大小的内存区域。n 是指针向量中的元素数量。

2.17.5. igraph_vector_ptr_destroy_all — 释放所有元素并销毁指针向量。

void igraph_vector_ptr_destroy_all(igraph_vector_ptr_t* v);

此函数等效于 igraph_vector_ptr_free_all() 之后接 igraph_vector_ptr_destroy()

参数: 

v:

指向要销毁的指针向量的指针。

时间复杂度:操作系统依赖,释放 O(n) 个指针所需的时间,每个指针都指向任意大小的内存区域,再加上释放 O(n) 字节所需的时间,n 是为指针向量分配的元素数量(不一定是向量中的元素数量)。

2.17.6. igraph_vector_ptr_size — 返回指针向量中的元素数量。

igraph_integer_t igraph_vector_ptr_size(const igraph_vector_ptr_t* v);

参数: 

v:

指针向量对象。

返回值: 

对象的大小,即存储的指针数量。

时间复杂度:O(1)。

2.17.7. igraph_vector_ptr_clear — 从指针向量中删除所有元素。

void igraph_vector_ptr_clear(igraph_vector_ptr_t* v);

此函数将指针向量的大小调整为零长度。请注意,指向的对象不会被释放,您应该对它们调用 igraph_free(),或者确保以某种其他方式释放它们的已分配内存,否则您会得到内存泄漏。如果您之前设置了项析构函数,则将对每个元素调用析构函数。

请注意,此函数的当前实现不会释放存储指针所需的内存,因此以这种方式缩小指针向量不会返回任何内存。此行为将来可能会更改。

参数: 

v:

要清除的指针向量。

时间复杂度:O(1)。

2.17.8. igraph_vector_ptr_push_back — 将一个元素追加到指针向量的末尾。

igraph_error_t igraph_vector_ptr_push_back(igraph_vector_ptr_t* v, void* e);

参数: 

v:

指针向量。

e:

要包含在指针向量中的新元素。

返回值: 

错误代码。

另请参阅: 

igraph_vector_push_back() 用于普通向量类型的相应操作。

时间复杂度:O(1) 或 O(n),n 是向量中的元素数量。指针向量实现确保 n 个后续 push_back 操作需要 O(n) 时间才能完成。

2.17.9. igraph_vector_ptr_pop_back — 删除并返回指针向量的最后一个元素。

void *igraph_vector_ptr_pop_back(igraph_vector_ptr_t *v);

使用空向量调用此函数是一个错误。

参数: 

v:

指针向量。

返回值: 

删除的最后一个元素。

时间复杂度:O(1)。

2.17.10. igraph_vector_ptr_insert — 将单个元素插入到指针向量中。

igraph_error_t igraph_vector_ptr_insert(igraph_vector_ptr_t* v, igraph_integer_t pos, void* e);

请注意,此函数不进行范围检查。插入会将元素从给定位置到向量末尾向右移动一个位置,并将新元素插入到给定位置创建的空白空间中。向量的大小将增加 1。

参数: 

v:

指针向量对象。

位置:

插入新元素的位置。

e:

插入的元素

2.17.11. igraph_vector_ptr_get — 访问指针向量的元素。

void *igraph_vector_ptr_get(const igraph_vector_ptr_t* v, igraph_integer_t pos);

参数: 

v:

指向指针向量的指针。

位置:

要返回的指针的索引。

返回值: 

位于 pos 位置的指针。

时间复杂度:O(1)。

2.17.12. igraph_vector_ptr_set — 分配给指针向量的元素。

void igraph_vector_ptr_set(igraph_vector_ptr_t* v, igraph_integer_t pos, void* value);

参数: 

v:

指向指针向量的指针。

位置:

要更新的指针的索引。

:

要在向量中设置的新指针。

时间复杂度:O(1)。

2.17.13. igraph_vector_ptr_resize — 调整指针向量的大小。

igraph_error_t igraph_vector_ptr_resize(igraph_vector_ptr_t* v, igraph_integer_t newsize);

请注意,如果向量变小,则此函数不会释放指向的对象,也不会对额外的元素调用项析构函数。

参数: 

v:

一个指针向量。

newsize:

指针向量的新大小。

返回值: 

错误代码。

时间复杂度:如果向量变小则为 O(1)。否则操作系统依赖,分配向量元素的内存所需的时间量。

2.17.14. igraph_vector_ptr_sort — 基于外部比较函数对指针向量进行排序。

void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int (*compar)(const void*, const void*));

有时需要基于指针引用的元素的属性对向量中的指针进行排序。此函数允许我们基于任意外部比较函数对向量进行排序,该函数接受两个 void * 指针 p1p2,并且如果第一个参数分别被认为小于、等于或大于第二个参数,则返回一个小于、等于或大于零的整数。p1p2 将指向向量中的指针,因此如果想要访问存储在 v 中的地址的基础对象,则必须对其进行双重解引用。

参数: 

v:

要排序的指针向量。

compar:

一个 qsort 兼容的比较函数。它必须采用指向指针向量的元素的指针。例如,如果指针向量包含 igraph_vector_t * 指针,则比较函数必须将其参数解释为 igraph_vector_t **

2.17.15. igraph_vector_ptr_sort_ind — 返回对指针向量进行排序的索引置换。

igraph_error_t igraph_vector_ptr_sort_ind(igraph_vector_ptr_t *v,
        igraph_vector_int_t *inds, cmp_t *cmp);

接受一个未排序的数组 v 作为输入,并计算一个索引数组 inds,使得 v[ inds[i] ],其中 i 从 0 开始递增,是一个有序数组(升序或降序,具体取决于 \v order)。相同元素的索引顺序未定义。

参数: 

v:

要排序的数组

inds:

索引的输出数组。必须初始化,但将调整大小

cmp:

一个比较器函数,它接受要排序的指针向量的两个元素(这些元素本身是指针上的常量指针),并且如果第一个指针“指向”的项小于第二个指针“指向”的项,则返回一个负值;如果它更大,则返回一个正值;如果两项相等,则返回零

返回值: 

错误代码。

此例程使用 C 库 qsort 例程。算法:1) 创建一个指向 v 元素的指针数组。2) 将此数组传递给 qsort。3) 排序后,指针值与第一个指针值之间的差异给出了其在数组中的原始位置。使用此来设置 inds 的值。

2.17.16. igraph_vector_ptr_permute — 根据索引向量就地置换指针向量的元素。

igraph_error_t igraph_vector_ptr_permute(igraph_vector_ptr_t* v, const igraph_vector_int_t* index);

此函数采用向量 v 和相应的索引向量 ind,并排列 v 的元素,使得在函数执行后,v[ind[i]] 被移动为 v[i]。

使用不表示有效排列的索引向量调用此函数是错误的。索引向量中的每个元素必须介于 0 和向量长度减一之间(包括),并且每个这样的元素必须只出现一次。该函数不会尝试验证索引向量。

此函数采用的索引向量与从 igraph_vector_ptr_sort_ind() 返回的索引向量兼容;传入来自 igraph_vector_ptr_sort_ind() 的索引向量将对原始向量进行排序。

作为一种特殊情况,此函数允许索引向量比要排列的向量,在这种情况下,索引向量中未出现的索引的元素将从向量中删除。

参数: 

v:

要排列的向量

索引:

索引向量

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:O(n),向量的大小。

2.17.17. igraph_vector_ptr_get_item_destructor — 获取此指针向量的当前项析构函数。

igraph_finally_func_t* igraph_vector_ptr_get_item_destructor(const igraph_vector_ptr_t *v);

项析构函数是一个函数,当调用 igraph_vector_ptr_destroy()、igraph_vector_ptr_destroy_all() 或 igraph_vector_ptr_free_all() 时,将对存储在此向量中的每个非空指针调用该函数。

返回值: 

当前的项析构函数。

时间复杂度:O(1)。

2.17.18. igraph_vector_ptr_set_item_destructor — 设置此指针向量的项析构函数。

igraph_finally_func_t* igraph_vector_ptr_set_item_destructor(
    igraph_vector_ptr_t *v, igraph_finally_func_t *func);

项析构函数是一个函数,当调用 igraph_vector_ptr_destroy()、igraph_vector_ptr_destroy_all() 或 igraph_vector_ptr_free_all() 时,将对存储在此向量中的每个非空指针调用该函数。

返回值: 

旧的项析构函数。

时间复杂度:O(1)。

2.17.19. IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR — 设置此指针向量的项析构函数(宏版本)。

#define IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(v, func)

此宏扩展为 igraph_vector_ptr_set_item_destructor(),唯一的区别是第二个参数会自动强制转换为 igraph_finally_func_t*。在大多数情况下都需要强制转换,因为我们使用的析构函数(例如 igraph_vector_destroy())采用指向某些具体的 igraph 数据类型的指针,而 igraph_finally_func_t 期望 void*

2.18. 已弃用的函数

2.18.1. igraph_vector_copy — 从另一个向量对象初始化一个向量(已弃用的别名)。

igraph_error_t igraph_vector_copy(igraph_vector_t *to,
                                  const igraph_vector_t *from);

警告

自版本 0.10 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_init_copy()

2.18.2. igraph_vector_e — 访问向量的元素(已弃用的别名)。

igraph_real_t igraph_vector_e(const igraph_vector_t *v, igraph_integer_t pos);

警告

自版本 0.10.0 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_get()

2.18.3. igraph_vector_e_ptr — 获取向量元素的地址。

igraph_real_t* igraph_vector_e_ptr(const igraph_vector_t *v, igraph_integer_t pos);

参数: 

v:

igraph_vector_t 对象。

位置:

元素的位置,第一个元素的位置为零。

返回值: 

指向所需元素的指针。

另请参阅: 

时间复杂度:O(1)。

2.18.4. igraph_vector_init_seq — 使用序列初始化向量,包括端点(已弃用)。

igraph_error_t igraph_vector_init_seq(igraph_vector_t *v, igraph_real_t from, igraph_real_t to);

该向量将包含数字 fromfrom+1、...、to。请注意,与 C 中范围的典型用法相反,两个端点都包括在内

警告

自版本 0.10.0 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_init_range()

参数: 

v:

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

:

序列中的下限(包括在内)。

:

序列中的上限(包括在内)。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:O(n),向量中的元素数量。

2.18.5. igraph_vector_ptr_copy — 从另一个指针向量初始化一个指针向量(已弃用的别名)。

igraph_error_t igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from);

警告

自版本 0.10 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_ptr_init_copy()

2.18.6. igraph_vector_ptr_e — 访问指针向量的元素(已弃用的别名)。

void *igraph_vector_ptr_e(const igraph_vector_ptr_t* v, igraph_integer_t pos);

警告

自版本 0.10.0 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_ptr_get()

2.18.7. igraph_vector_qsort_ind — 返回对向量进行排序的索引置换(已弃用的别名)。

igraph_error_t igraph_vector_qsort_ind(const igraph_vector_t *v,
                                                 igraph_vector_int_t *inds, igraph_order_t order);

警告

自版本 0.10.14 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_sort_ind()

2.18.8. igraph_vector_binsearch2 — 二分查找,不返回索引。

igraph_bool_t igraph_vector_binsearch2(const igraph_vector_t *v,
                                                  igraph_real_t what);

警告

自版本 0.10.14 起已弃用。请勿在新代码中使用此函数;请改用 igraph_vector_contains_sorted()

3. 矩阵

3.1. 关于 igraph_matrix_t 对象

此类型只是 igraph_vector_t 的接口。

igraph_matrix_t 类型通常在 O(n) 空间中存储 n 个元素,但并非总是如此。请参阅向量类型的文档。

3.2. 矩阵构造函数和析构函数

3.2.1. igraph_matrix_init — 初始化矩阵。

igraph_error_t igraph_matrix_init(
        igraph_matrix_t *m, igraph_integer_t nrow, igraph_integer_t ncol);

每个矩阵在使用之前都需要初始化。这通过调用此函数来完成。如果不再需要矩阵,则必须将其销毁;请参阅 igraph_matrix_destroy()

参数: 

m:

指向尚未初始化的矩阵对象的指针,要初始化。

nrow:

矩阵中的行数。

ncol:

矩阵中的列数。

返回值: 

错误代码。

时间复杂度:通常为 O(n),n 是矩阵中的元素数量。

3.2.2. igraph_matrix_init_array — 从普通 C 数组初始化矩阵(构造函数)。

igraph_error_t igraph_matrix_init_array(
        igraph_matrix_t *m, const igraph_real_t *data,
        igraph_integer_t nrow, igraph_integer_t ncol,
        igraph_matrix_storage_t storage);

假定该数组以连续的方式存储矩阵数据,无论是列优先格式还是行优先格式。换句话说,data 可能会存储串联的矩阵列或串联的矩阵行。从列优先数据构造矩阵的速度更快,因为这是 igraph 的本机存储格式。

参数: 

v:

指向未初始化的矩阵对象的指针。

数据:

一个常规的 C 数组,以列优先顺序存储矩阵的元素,即首先存储第一列的元素,然后是第二列,依此类推。

nrow:

矩阵中的行数。

ncol:

矩阵中的列数。

storage:

如果数组采用行优先格式,则为 IGRAPH_ROW_MAJOR;如果数组采用列优先格式,则为 IGRAPH_COLUMN_MAJOR

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:操作系统特定,通常为 O(nrow ncol)。

3.2.3. igraph_matrix_init_copy — 复制矩阵。

igraph_error_t igraph_matrix_init_copy(igraph_matrix_t *to, const igraph_matrix_t *from);

通过从现有矩阵复制来创建一个矩阵对象。

参数: 

:

指向未初始化的矩阵对象的指针。

:

要复制的已初始化的矩阵对象。

返回值: 

错误代码,如果内存不足以分配新矩阵,则为 IGRAPH_ENOMEM

时间复杂度:O(n),矩阵中的元素数量。

3.2.4. igraph_matrix_destroy — 销毁矩阵对象。

void igraph_matrix_destroy(igraph_matrix_t *m);

此函数释放为矩阵对象分配的所有内存。销毁的对象需要重新初始化才能再次使用。

参数: 

m:

要销毁的矩阵。

时间复杂度:操作系统相关。

3.3. 初始化元素

3.3.1. igraph_matrix_null — 将矩阵中的所有元素设置为零。

void igraph_matrix_null(igraph_matrix_t *m);

参数: 

m:

指向已初始化的矩阵对象的指针。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.3.2. igraph_matrix_fill — 使用一个元素填充。

void igraph_matrix_fill(igraph_matrix_t *m, igraph_real_t e);

将矩阵设置为一个常数矩阵。

参数: 

m:

输入矩阵。

e:

要设置的元素。

时间复杂度:O(mn),元素的数量。

3.4.  访问矩阵的元素

3.4.1. MATRIX — 访问矩阵的元素。

#define MATRIX(m,i,j)

请注意,目前没有范围检查。此功能稍后可能会被重新定义为一个合适的函数。

参数: 

m:

矩阵对象。

i:

行的索引,从零开始。

j:

列的索引,从零开始。

时间复杂度:O(1)。

3.4.2. igraph_matrix_get — 从矩阵中提取一个元素。

igraph_real_t igraph_matrix_get(const igraph_matrix_t *m,
                                igraph_integer_t row, igraph_integer_t col);

如果出于某种原因需要一个函数,并且无法使用 MATRIX 宏,请使用此函数。请注意,不执行范围检查。

参数: 

m:

输入矩阵。

row:

行索引。

col:

列索引。

返回值: 

给定行和列中的元素。

时间复杂度:O(1)。

3.4.3. igraph_matrix_get_ptr — 指向矩阵元素的指针。

igraph_real_t* igraph_matrix_get_ptr(const igraph_matrix_t *m,
                                       igraph_integer_t row, igraph_integer_t col);

该函数返回指向元素的指针。不执行范围检查。

参数: 

m:

输入矩阵。

row:

行索引。

col:

列索引。

返回值: 

指向给定行和列中的元素的指针。

时间复杂度:O(1)。

3.4.4. igraph_matrix_set — 设置一个元素。

void igraph_matrix_set(
        igraph_matrix_t* m, igraph_integer_t row, igraph_integer_t col,
        igraph_real_t value);

设置矩阵的一个元素。不执行范围检查。

参数: 

m:

输入矩阵。

row:

行索引。

col:

列索引。

:

元素的新值。

时间复杂度:O(1)。

3.5. 矩阵视图

3.5.1. igraph_matrix_view — 创建一个矩阵视图到现有数组中。

const igraph_matrix_t* igraph_matrix_view(
        const igraph_matrix_t *m, const igraph_real_t *data,
        igraph_integer_t nrow, igraph_integer_t ncol);

此函数允许您将现有 C 数组视为矩阵。矩阵的元素假定以列优先顺序存储在数组中,即首先存储第一列的元素,然后是第二列,依此类推。

由于此函数创建了一个到现有数组的视图,因此您在完成操作后不得销毁 igraph_matrix_t 对象。同样,您不得在其上调用任何可能尝试修改矩阵大小的函数。修改矩阵中的元素将修改底层数组,因为两者共享相同的内存块。

参数: 

m:

指向尚未初始化的矩阵对象的指针,将在其中创建视图。

数据:

矩阵提供视图的数组。

nrow:

矩阵中的行数。

ncol:

矩阵中的列数。

返回值: 

指向矩阵对象的指针,与 m 参数相同,为了方便起见。

时间复杂度:O(1)。

3.5.2. igraph_matrix_view_from_vector — 创建一个矩阵视图,将现有向量视为矩阵。

const igraph_matrix_t *igraph_matrix_view_from_vector(
    const igraph_matrix_t *m, const igraph_vector_t *v,
    igraph_integer_t nrow
);

此函数允许您将现有的 igraph 向量视为矩阵。矩阵的元素假定以列优先顺序存储在向量中,即首先存储第一列的元素,然后是第二列,依此类推。

由于此函数创建了一个到现有向量的视图,因此您在完成操作后不得销毁 igraph_matrix_t 对象。同样,您不得在其上调用任何可能尝试修改向量大小的函数。修改矩阵中的元素将修改底层向量,因为两者共享相同的内存块。

此外,您不得尝试通过任何向量操作来增加底层向量,因为这可能会导致向量的后备内存块重新分配,并且矩阵视图不会收到有关重新分配的通知,因此它将在之后指向无效的内存区域。

参数: 

m:

指向尚未初始化的矩阵对象的指针,将在其中创建视图。

v:

矩阵将提供视图的向量。

nrow:

矩阵中的行数。列数将从向量的大小隐式导出。如果向量中的项目数不能被行数整除,则向量的最后几个元素将不会被视图覆盖。

返回值: 

错误代码。

时间复杂度:O(1)。

3.6. 复制矩阵

3.6.1. igraph_matrix_copy_to — 将矩阵复制到常规 C 数组。

void igraph_matrix_copy_to(const igraph_matrix_t *m, igraph_real_t *to);

矩阵按列复制,因为这是大多数程序和语言使用的格式。C 数组的大小应足够大;(当然)没有范围检查。

参数: 

m:

指向已初始化的矩阵对象的指针。

:

指向 C 数组的指针;复制数据的位置。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.6.2. igraph_matrix_update — 从另一个矩阵更新。

igraph_error_t igraph_matrix_update(igraph_matrix_t *to,
                                    const igraph_matrix_t *from);

此函数在矩阵 to 中复制 from。请注意,to 必须已初始化。

参数: 

:

结果矩阵。

:

要复制的矩阵;它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),元素的数量。

3.6.3. igraph_matrix_swap — 交换两个矩阵。

igraph_error_t igraph_matrix_swap(igraph_matrix_t *m1, igraph_matrix_t *m2);

两个矩阵的内容将被交换。

参数: 

m1:

第一个矩阵。

m2:

第二个矩阵。

返回值: 

错误代码。

时间复杂度:O(1)。

3.7. 行和列上的操作

3.7.1. igraph_matrix_get_row — 提取一行。

igraph_error_t igraph_matrix_get_row(const igraph_matrix_t *m,
                                     igraph_vector_t *res, igraph_integer_t index);

从矩阵中提取一行,并将其作为向量返回。

参数: 

m:

输入矩阵。

res:

指向已初始化的向量的指针;如果需要,将调整其大小。

index:

要选择的行的索引。

返回值: 

错误代码。

时间复杂度:O(n),矩阵中的列数。

3.7.2. igraph_matrix_get_col — 选择一列。

igraph_error_t igraph_matrix_get_col(const igraph_matrix_t *m,
                                     igraph_vector_t *res,
                                     igraph_integer_t index);

提取矩阵的一列,并将其作为向量返回。

参数: 

m:

输入矩阵。

res:

结果将存储在此向量中。它应该被初始化,并且会根据需要调整大小。

index:

要选择的列的索引。

返回值: 

错误代码。

时间复杂度:O(n),矩阵中的行数。

3.7.3. igraph_matrix_set_row — 从向量设置一行。

igraph_error_t igraph_matrix_set_row(igraph_matrix_t *m,
                                     const igraph_vector_t *v, igraph_integer_t index);

用给定的向量设置一行的元素。其效果是将行 index 设置为具有向量 v 中的元素。向量的长度和矩阵中的列数必须匹配,否则会触发错误。

参数: 

m:

输入矩阵。

v:

包含行的新元素的向量。

index:

要设置的行的索引。

返回值: 

错误代码。

时间复杂度:O(n),矩阵中的列数。

3.7.4. igraph_matrix_set_col — 从向量设置一列。

igraph_error_t igraph_matrix_set_col(igraph_matrix_t *m,
                                     const igraph_vector_t *v, igraph_integer_t index);

用给定的向量设置一列的元素。实际上,列 index 将被设置为向量 v 中的元素。向量的长度和矩阵中的行数必须匹配,否则会触发错误。

参数: 

m:

输入矩阵。

v:

包含列的新元素的向量。

index:

要设置的列的索引。

返回值: 

错误代码。

时间复杂度:O(m),矩阵中的行数。

3.7.5. igraph_matrix_swap_rows — 交换两行。

igraph_error_t igraph_matrix_swap_rows(igraph_matrix_t *m,
                                       igraph_integer_t i, igraph_integer_t j);

交换矩阵中的两行。

参数: 

m:

输入矩阵。

i:

第一行的索引。

j:

第二行的索引。

返回值: 

错误代码。

时间复杂度:O(n),列数。

3.7.6. igraph_matrix_swap_cols — 交换两列。

igraph_error_t igraph_matrix_swap_cols(igraph_matrix_t *m,
                                       igraph_integer_t i, igraph_integer_t j);

交换矩阵中的两列。

参数: 

m:

输入矩阵。

i:

第一列的索引。

j:

第二列的索引。

返回值: 

错误代码。

时间复杂度:O(m),行数。

3.7.7. igraph_matrix_select_rows — 选择矩阵的一些行。

igraph_error_t igraph_matrix_select_rows(const igraph_matrix_t *m,
        igraph_matrix_t *res,
        const igraph_vector_int_t *rows);

此函数选择矩阵的一些行,并在新矩阵中返回它们。结果矩阵应该在调用函数之前被初始化。

参数: 

m:

输入矩阵。

res:

结果矩阵。它应该被初始化,并且会根据需要调整大小。

rows:

向量;它包含要提取的行索引(从零开始)。请注意,不执行范围检查。

返回值: 

错误代码。

时间复杂度:O(nm),n 是行数,m 是结果矩阵的列数。

3.7.8. igraph_matrix_select_cols — 选择矩阵的一些列。

igraph_error_t igraph_matrix_select_cols(const igraph_matrix_t *m,
        igraph_matrix_t *res,
        const igraph_vector_int_t *cols);

此函数选择矩阵的一些列,并在新矩阵中返回它们。结果矩阵应该在调用函数之前被初始化。

参数: 

m:

输入矩阵。

res:

结果矩阵。它应该被初始化,并且会根据需要调整大小。

cols:

向量;它包含要提取的列索引(从零开始)。请注意,不执行范围检查。

返回值: 

错误代码。

时间复杂度:O(nm),n 是行数,m 是结果矩阵的列数。

3.7.9. igraph_matrix_select_rows_cols — 选择矩阵的一些行和列。

igraph_error_t igraph_matrix_select_rows_cols(const igraph_matrix_t *m,
        igraph_matrix_t *res,
        const igraph_vector_int_t *rows,
        const igraph_vector_int_t *cols);

此函数选择矩阵的一些行和列,并在新矩阵中返回它们。结果矩阵应该在调用函数之前被初始化。

参数: 

m:

输入矩阵。

res:

结果矩阵。它应该被初始化,并且会根据需要调整大小。

rows:

向量;它包含要提取的行索引(从零开始)。请注意,不执行范围检查。

cols:

向量;它包含要提取的列索引(从零开始)。请注意,不执行范围检查。

返回值: 

错误代码。

时间复杂度:O(nm),n 是行数,m 是结果矩阵的列数。

3.8. 矩阵运算

3.8.1. igraph_matrix_add_constant — 将一个常数加到每个元素。

void igraph_matrix_add_constant(igraph_matrix_t *m, igraph_real_t plus);

参数: 

m:

输入矩阵。

plud:

要添加的常量。

时间复杂度:O(mn),元素的数量。

3.8.2. igraph_matrix_scale — 将矩阵的每个元素乘以一个常数。

void igraph_matrix_scale(igraph_matrix_t *m, igraph_real_t by);

参数: 

m:

矩阵。

by:

常量。

在 0.2 版本中添加。

时间复杂度:O(n),矩阵中的元素数量。

3.8.3. igraph_matrix_add — 添加两个矩阵。

igraph_error_t igraph_matrix_add(igraph_matrix_t *m1,
                                 const igraph_matrix_t *m2);

m2 加到 m1,并将结果存储在 m1 中。矩阵的维度必须匹配。

参数: 

m1:

第一个矩阵;结果将存储在这里。

m2:

第二个矩阵;它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),元素的数量。

3.8.4. igraph_matrix_sub — 两个矩阵的差。

igraph_error_t igraph_matrix_sub(igraph_matrix_t *m1,
                                 const igraph_matrix_t *m2);

m1 中减去 m2,并将结果存储在 m1 中。两个矩阵的维度必须匹配。

参数: 

m1:

第一个矩阵;结果存储在这里。

m2:

第二个矩阵;它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),元素的数量。

3.8.5. igraph_matrix_mul_elements — 元素矩阵乘法。

igraph_error_t igraph_matrix_mul_elements(igraph_matrix_t *m1,
        const igraph_matrix_t *m2);

m1m2 逐元素相乘,并将结果存储在 m1 中。两个矩阵的维度必须匹配。

参数: 

m1:

第一个矩阵;结果存储在这里。

m2:

第二个矩阵;它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),元素的数量。

3.8.6. igraph_matrix_div_elements — 元素除法。

igraph_error_t igraph_matrix_div_elements(igraph_matrix_t *m1,
        const igraph_matrix_t *m2);

m1 除以 m2 逐元素相除,并将结果存储在 m1 中。两个矩阵的维度必须匹配。

参数: 

m1:

被除数。结果存储在这里。

m2:

除数。它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),元素的数量。

3.8.7. igraph_matrix_sum — 元素的和。

igraph_real_t igraph_matrix_sum(const igraph_matrix_t *m);

返回矩阵元素的和。

参数: 

m:

输入矩阵。

返回值: 

元素的总和。

时间复杂度:O(mn),矩阵中元素的数量。

3.8.8. igraph_matrix_prod — 所有矩阵元素的乘积。

igraph_real_t igraph_matrix_prod(const igraph_matrix_t *m);

请注意,即使对于不太大的矩阵,此函数也容易导致溢出。不检查溢出。

参数: 

m:

输入矩阵。

返回值: 

元素的乘积。

时间复杂度:O(mn),元素的数量。

3.8.9. igraph_matrix_rowsum — 按行求和。

igraph_error_t igraph_matrix_rowsum(const igraph_matrix_t *m,
                                    igraph_vector_t *res);

计算每行中元素的和。

参数: 

m:

输入矩阵。

res:

指向已初始化的向量的指针;结果存储在这里。如果需要,将调整其大小。

返回值: 

错误代码。

时间复杂度:O(mn),矩阵中元素的数量。

3.8.10. igraph_matrix_colsum — 按列求和。

igraph_error_t igraph_matrix_colsum(const igraph_matrix_t *m,
                                    igraph_vector_t *res);

计算每列中元素的和。

参数: 

m:

输入矩阵。

res:

指向已初始化的向量的指针;结果存储在这里。如果需要,将调整其大小。

返回值: 

错误代码。

时间复杂度:O(mn),矩阵中元素的数量。

3.8.11. igraph_matrix_transpose — 矩阵的转置。

igraph_error_t igraph_matrix_transpose(igraph_matrix_t *m);

计算矩阵的转置。当矩阵为非正方形时,此函数会重新分配用于矩阵的存储空间。

参数: 

m:

输入(和输出)矩阵。

返回值: 

错误代码。

时间复杂度:O(mn),矩阵中元素的数量。

3.9. 矩阵比较

3.9.1. igraph_matrix_all_e — 所有元素都相等吗?

igraph_bool_t igraph_matrix_all_e(const igraph_matrix_t *lhs,
        const igraph_matrix_t *rhs);

检查两个矩阵的元素是否相等。对于包含浮点值的矩阵,请考虑使用 igraph_matrix_all_almost_e()

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

返回值: 

如果 lhs 中的元素都等于 rhs 中对应的元素,则为 True。如果矩阵的维度不匹配,则返回 false。

时间复杂度:O(nm),矩阵的大小。

3.9.2. igraph_matrix_all_almost_e — 所有元素都几乎相等吗?

igraph_bool_t igraph_matrix_all_almost_e(const igraph_matrix_t *lhs,
                                         const igraph_matrix_t *rhs,
                                         igraph_real_t eps);

检查两个矩阵的元素是否在相对容差范围内相等。

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

eps:

相对容差,详见 igraph_almost_equals()

返回值: 

如果两个矩阵几乎相等,则为 True;如果至少有一个不同的元素,或者矩阵的维度不同,则为 false。

3.9.3. igraph_matrix_all_l — 所有元素都小于吗?

igraph_bool_t igraph_matrix_all_l(const igraph_matrix_t *lhs,
        const igraph_matrix_t *rhs);

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

返回值: 

如果 lhs 中的元素都小于 rhs 中对应的元素,则为 True。如果矩阵的维度不匹配,则返回 false。

时间复杂度:O(nm),矩阵的大小。

3.9.4. igraph_matrix_all_g — 所有元素都大于吗?

igraph_bool_t igraph_matrix_all_g(const igraph_matrix_t *lhs,
        const igraph_matrix_t *rhs);

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

返回值: 

如果 lhs 中的元素都大于 rhs 中对应的元素,则为 True。如果矩阵的维度不匹配,则返回 false。

时间复杂度:O(nm),矩阵的大小。

3.9.5. igraph_matrix_all_le — 所有元素都小于或等于吗?

igraph_bool_t
igraph_matrix_all_le(const igraph_matrix_t *lhs,
                                const igraph_matrix_t *rhs);

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

返回值: 

如果 lhs 中的元素都小于或等于 rhs 中对应的元素,则为 True。如果矩阵的维度不匹配,则返回 false。

时间复杂度:O(nm),矩阵的大小。

3.9.6. igraph_matrix_all_ge — 所有元素都大于或等于吗?

igraph_bool_t
igraph_matrix_all_ge(const igraph_matrix_t *lhs,
                                const igraph_matrix_t *rhs);

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

返回值: 

如果 lhs 中的元素都大于或等于 rhs 中对应的元素,则为 True。如果矩阵的维度不匹配,则返回 false。

时间复杂度:O(nm),矩阵的大小。

3.9.7. igraph_matrix_zapsmall — 将矩阵的小元素替换为精确的零。

igraph_error_t igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol);

幅度小于给定绝对容差的矩阵元素将被替换为精确的零。默认容差对应于 igraph_real_t 的可表示数字的三分之二,即 DBL_EPSILON^(2/3),大约为 10^-10

参数: 

m:

要处理的矩阵,它将就地更改。

tol:

容差值。幅度小于此值的数字将被替换为零。传入零以使用默认容差。不能为负数。

返回值: 

错误代码。

另请参阅: 

igraph_matrix_all_almost_e()igraph_almost_equals() 以执行具有相对容差的比较。

3.10. 组合矩阵

3.10.1. igraph_matrix_rbind — 按行组合两个矩阵。

igraph_error_t igraph_matrix_rbind(igraph_matrix_t *to,
                                   const igraph_matrix_t *from);

此函数将 from 的行放置在 to 的行的下方,并将结果存储在 to 中。两个矩阵中的列数必须匹配。

参数: 

:

上矩阵;结果也存储在这里。

:

下矩阵。它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),新创建的矩阵中元素的数量。

3.10.2. igraph_matrix_cbind — 按列组合矩阵。

igraph_error_t igraph_matrix_cbind(igraph_matrix_t *to,
                                   const igraph_matrix_t *from);

此函数将 from 的列放置在 to 的右侧,并将结果存储在 to 中。

参数: 

:

左矩阵;结果也存储在这里。

:

右矩阵。它保持不变。

返回值: 

错误代码。

时间复杂度:O(mn),新矩阵上的元素数。

3.11. 查找最小值和最大值

3.11.1. igraph_matrix_min — 矩阵的最小元素。

igraph_real_t igraph_matrix_min(const igraph_matrix_t *m);

矩阵必须是非空的。

参数: 

m:

输入矩阵。

返回值: 

m 的最小元素,如果任何元素是 NaN,则为 NaN。

时间复杂度:O(mn),矩阵中元素的数量。

3.11.2. igraph_matrix_max — 矩阵的最大元素。

igraph_real_t igraph_matrix_max(const igraph_matrix_t *m);

如果矩阵是空的,则返回一个任意数字。

参数: 

m:

矩阵对象。

返回值: 

m 的最大元素,如果任何元素是 NaN,则为 NaN。

在 0.2 版本中添加。

时间复杂度:O(mn),矩阵中元素的数量。

3.11.3. igraph_matrix_which_min — 最小元素的索引。

void igraph_matrix_which_min(
        const igraph_matrix_t *m, igraph_integer_t *i, igraph_integer_t *j);

矩阵必须是非空的。如果最小元素不是唯一的,则返回第一个此类元素的索引。如果矩阵包含 NaN 值,则返回第一个 NaN 值的索引。

参数: 

m:

矩阵。

i:

指向 igraph_integer_t 的指针。最小值的行索引存储在这里。

j:

指向 igraph_integer_t 的指针。最小值的列索引存储在这里。

时间复杂度:O(mn),元素的数量。

3.11.4. igraph_matrix_which_max — 最大元素的索引。

void igraph_matrix_which_max(
        const igraph_matrix_t *m, igraph_integer_t *i, igraph_integer_t *j);

矩阵必须是非空的。如果最大元素不是唯一的,则返回第一个此类元素的索引。如果矩阵包含 NaN 值,则返回第一个 NaN 值的索引。

参数: 

m:

矩阵。

i:

指向 igraph_integer_t 的指针。最大值的行索引存储在这里。

j:

指向 igraph_integer_t 的指针。最大值的列索引存储在这里。

时间复杂度:O(mn),元素的数量。

3.11.5. igraph_matrix_minmax — 矩阵的最小和最大元素。

void igraph_matrix_minmax(const igraph_matrix_t *m,
                                    igraph_real_t *min, igraph_real_t *max);

如果您想要矩阵的最小和最大元素,则很方便。矩阵只会被遍历一次。矩阵必须是非空的。如果一个矩阵包含至少一个 NaN,则 minmax 都将是 NaN。

参数: 

m:

输入矩阵。它必须包含至少一个元素。

min:

指向基本类型变量的指针。最小值存储在这里。

max:

指向基本类型变量的指针。最大值存储在这里。

时间复杂度:O(mn),元素的数量。

3.11.6. igraph_matrix_which_minmax — 最小和最大元素的索引。

void igraph_matrix_which_minmax(const igraph_matrix_t *m,
        igraph_integer_t *imin, igraph_integer_t *jmin,
        igraph_integer_t *imax, igraph_integer_t *jmax);

如果您需要最小和最大元素的索引,则很方便。矩阵只会被遍历一次。矩阵必须是非空的。如果最小值或最大值不是唯一的,则分别返回第一个最小值或第一个最大值的索引。如果一个矩阵包含至少一个 NaN,则 which_minwhich_max 都将指向第一个 NaN 值。

参数: 

m:

输入矩阵。

imin:

指向 igraph_integer_t 的指针,最小值的行索引存储在这里。

jmin:

指向 igraph_integer_t 的指针,最小值的列索引存储在这里。

imax:

指向 igraph_integer_t 的指针,最大值的行索引存储在这里。

jmax:

指向 igraph_integer_t 的指针,最大值的列索引存储在这里。

时间复杂度:O(mn),元素的数量。

3.12. 矩阵属性

3.12.1. igraph_matrix_empty — 矩阵为空吗?

igraph_bool_t igraph_matrix_empty(const igraph_matrix_t *m);

矩阵可能有零行或零列,甚至两者都有。此函数检查这些。

参数: 

m:

输入矩阵。

返回值: 

布尔值,如果矩阵包含零元素,则为 true,否则为 false

时间复杂度:O(1)。

3.12.2. igraph_matrix_isnull — 检查是否为空矩阵。

igraph_bool_t igraph_matrix_isnull(const igraph_matrix_t *m);

检查所有元素是否为零。

参数: 

m:

输入矩阵。

返回值: 

布尔值,如果 m 仅包含零,则为 true,否则为 false

时间复杂度:O(mn),元素的数量。

3.12.3. igraph_matrix_size — 矩阵中的元素数。

igraph_integer_t igraph_matrix_size(const igraph_matrix_t *m);

参数: 

m:

指向已初始化的矩阵对象的指针。

返回值: 

矩阵的大小。

时间复杂度:O(1)。

3.12.4. igraph_matrix_capacity — 返回为矩阵分配的元素数。

igraph_integer_t igraph_matrix_capacity(const igraph_matrix_t *m);

请注意,这可能与矩阵的大小不同(如 igraph_matrix_size() 查询),并指定矩阵可以容纳多少个元素,而无需重新分配。

参数: 

v:

指向要查询的(先前初始化的)矩阵对象的指针。

返回值: 

已分配容量。

另请参阅: 

时间复杂度:O(1)。

3.12.5. igraph_matrix_nrow — 矩阵中的行数。

igraph_integer_t igraph_matrix_nrow(const igraph_matrix_t *m);

参数: 

m:

指向已初始化的矩阵对象的指针。

返回值: 

矩阵中的行数。

时间复杂度:O(1)。

3.12.6. igraph_matrix_ncol — 矩阵中的列数。

igraph_integer_t igraph_matrix_ncol(const igraph_matrix_t *m);

参数: 

m:

指向已初始化的矩阵对象的指针。

返回值: 

矩阵中的列数。

时间复杂度:O(1)。

3.12.7. igraph_matrix_is_symmetric — 矩阵是对称的吗?

igraph_bool_t igraph_matrix_is_symmetric(const igraph_matrix_t *m);

根据定义,非正方形矩阵不是对称的。

参数: 

m:

输入矩阵。

返回值: 

布尔值,如果矩阵是正方形且对称的,则为 true,否则为 false

时间复杂度:O(mn),元素的数量。对于非正方形矩阵,为 O(1)。

3.12.8. igraph_matrix_maxdifference — 两个矩阵之间的最大绝对差。

igraph_real_t igraph_matrix_maxdifference(const igraph_matrix_t *m1,
        const igraph_matrix_t *m2);

计算两个矩阵的最大绝对差。两个矩阵都必须是非空的。如果它们的维度不同,则会发出警告,并且通过从两个矩阵中按列向量执行比较。较大的向量中的剩余元素将被忽略。

参数: 

m1:

第一个矩阵。

m2:

第二个矩阵。

返回值: 

m1 - m2 中具有最大绝对值的元素。

时间复杂度:O(mn),较小矩阵中的元素数。

3.13. 搜索元素

3.13.1. igraph_matrix_contains — 搜索元素。

igraph_bool_t igraph_matrix_contains(const igraph_matrix_t *m,
        igraph_real_t e);

在矩阵中搜索给定的元素。

参数: 

m:

输入矩阵。

e:

要搜索的元素。

返回值: 

布尔值,如果矩阵包含 e,则为 true,否则为 false

时间复杂度:O(mn),元素的数量。

3.13.2. igraph_matrix_search — 从给定位置搜索。

igraph_bool_t igraph_matrix_search(const igraph_matrix_t *m,
        igraph_integer_t from, igraph_real_t what, igraph_integer_t *pos,
        igraph_integer_t *row, igraph_integer_t *col);

在矩阵中搜索元素,并从给定位置开始搜索。搜索按列执行。

参数: 

m:

输入矩阵。

:

要从中搜索的位置,位置按列枚举。

what:

要搜索的元素。

位置:

指向 igraph_integer_t 的指针。如果找到该元素,则将其设置为其首次出现的位置。

row:

指向 igraph_integer_t 的指针。如果找到该元素,则将其设置为其行索引。

col:

指向 igraph_integer_t 的指针。如果找到该元素,则将其设置为其列索引。

返回值: 

布尔值,如果找到该元素,则为 true,否则为 false

时间复杂度:O(mn),元素的数量。

3.14. 调整大小操作

3.14.1. igraph_matrix_resize — 调整矩阵大小。

igraph_error_t igraph_matrix_resize(igraph_matrix_t *m, igraph_integer_t nrow, igraph_integer_t ncol);

此函数通过添加更多元素来调整矩阵大小。调整大小后,矩阵包含任意数据。也就是说,调用此函数后,您不能期望矩阵中的元素 (i,j) 与之前保持相同。

参数: 

m:

指向已初始化的矩阵对象的指针。

nrow:

调整大小后的矩阵中的行数。

ncol:

调整大小后的矩阵中的列数。

返回值: 

错误代码。

时间复杂度:如果矩阵变小,则为 O(1);如果变大,通常为 O(n),其中 n 是调整大小后的矩阵中的元素数量。

3.14.2. igraph_matrix_resize_min — 释放矩阵未使用的内存。

void igraph_matrix_resize_min(igraph_matrix_t *m);

此函数尝试释放矩阵未使用的保留存储空间。

参数: 

m:

指向已初始化矩阵的指针。

另请参阅: 

时间复杂度:依赖于操作系统,最坏情况下为 O(n)。

3.14.3. igraph_matrix_add_rows — 向矩阵添加行。

igraph_error_t igraph_matrix_add_rows(igraph_matrix_t *m, igraph_integer_t n);

参数: 

m:

矩阵对象。

n:

要添加的行数。

返回值: 

错误代码,如果操作没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:与新的调整大小后的矩阵的元素数量呈线性关系。

3.14.4. igraph_matrix_add_cols — 向矩阵添加列。

igraph_error_t igraph_matrix_add_cols(igraph_matrix_t *m, igraph_integer_t n);

参数: 

m:

矩阵对象。

n:

要添加的列数。

返回值: 

错误代码,如果没有足够的内存来执行操作,则为 IGRAPH_ENOMEM

时间复杂度:与新的调整大小后的矩阵的元素数量呈线性关系。

3.14.5. igraph_matrix_remove_row — 移除一行。

igraph_error_t igraph_matrix_remove_row(igraph_matrix_t *m, igraph_integer_t row);

从矩阵中移除一行。

参数: 

m:

输入矩阵。

row:

要移除的行的索引。

返回值: 

错误代码。

时间复杂度:O(mn),矩阵中元素的数量。

3.14.6. igraph_matrix_remove_col — 从矩阵中移除一列。

igraph_error_t igraph_matrix_remove_col(igraph_matrix_t *m, igraph_integer_t col);

参数: 

m:

矩阵对象。

col:

要移除的列。

返回值: 

错误代码,始终返回成功。

时间复杂度:与新的调整大小后的矩阵的元素数量呈线性关系。

3.15. 复矩阵运算

3.15.1. igraph_matrix_complex_real — 给出复矩阵的实部。

igraph_error_t igraph_matrix_complex_real(const igraph_matrix_complex_t *m,
                               igraph_matrix_t *real);

参数: 

m:

指向复矩阵的指针。

实部:

指向已初始化矩阵的指针。结果将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.15.2. igraph_matrix_complex_imag — 给出复矩阵的虚部。

igraph_error_t igraph_matrix_complex_imag(const igraph_matrix_complex_t *m,
                               igraph_matrix_t *imag);

参数: 

m:

指向复矩阵的指针。

虚部:

指向已初始化矩阵的指针。结果将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.15.3. igraph_matrix_complex_realimag — 给出复矩阵的实部和虚部。

igraph_error_t igraph_matrix_complex_realimag(const igraph_matrix_complex_t *m,
                                   igraph_matrix_t *real,
                                   igraph_matrix_t *imag);

参数: 

m:

指向复矩阵的指针。

实部:

指向已初始化矩阵的指针。实部将存储在此处。

虚部:

指向已初始化矩阵的指针。虚部将存储在此处。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.15.4. igraph_matrix_complex_create — 从实部和虚部创建复矩阵。

igraph_error_t igraph_matrix_complex_create(igraph_matrix_complex_t *m,
                                 const igraph_matrix_t *real,
                                 const igraph_matrix_t *imag);

参数: 

m:

指向未初始化的复矩阵的指针。

实部:

指向复矩阵实部的指针。

虚部:

指向复矩阵虚部的指针。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.15.5. igraph_matrix_complex_create_polar — 从幅度和角度创建复矩阵。

igraph_error_t igraph_matrix_complex_create_polar(igraph_matrix_complex_t *m,
                                       const igraph_matrix_t *r,
                                       const igraph_matrix_t *theta);

参数: 

m:

指向未初始化的复矩阵的指针。

r:

指向包含幅度的实矩阵的指针。

theta:

指向包含参数(相位角)的实矩阵的指针。

返回值: 

错误代码。

时间复杂度:O(n),其中 n 是矩阵中元素的数量。

3.15.6. igraph_matrix_complex_all_almost_e — 所有元素是否几乎相等?

igraph_bool_t igraph_matrix_complex_all_almost_e(igraph_matrix_complex_t *lhs,
                                                  igraph_matrix_complex_t *rhs,
                                                  igraph_real_t eps);

检查两个复矩阵的元素是否在相对容差范围内相等。

参数: 

lhs:

第一个矩阵。

rhs:

第二个矩阵。

eps:

相对容差,有关详细信息,请参见 igraph_complex_almost_equals()

返回值: 

如果两个矩阵几乎相等,则为 True;如果至少有一个不同的元素,或者矩阵的维度不同,则为 false。

3.15.7. igraph_matrix_complex_zapsmall — 将复矩阵的小元素替换为精确的零。

igraph_error_t igraph_matrix_complex_zapsmall(igraph_matrix_complex_t *m, igraph_real_t tol);

igraph_matrix_zapsmall() 类似,小元素将被零替换。该操作分别在数字的实部和虚部上执行。这样,具有较大实部和微小虚部的复数将有效地转换为实数。默认容差对应于 igraph_real_t 的可表示数字的三分之二,即 DBL_EPSILON^(2/3),大约为 10^-10

参数: 

m:

要处理的矩阵,它将就地更改。

tol:

容差值。实部和虚部小于此幅度的部分将被替换为零。传入零以使用默认容差。不能为负。

返回值: 

错误代码。

另请参阅: 

igraph_matrix_complex_all_almost_e()igraph_complex_almost_equals() 执行具有相对容差的比较。

3.16. 已弃用的函数

3.16.1. igraph_matrix_copy — 复制矩阵(已弃用的别名)。

igraph_error_t igraph_matrix_copy(igraph_matrix_t *to, const igraph_matrix_t *from);

警告

自 0.10 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_matrix_init_copy()

3.16.2. igraph_matrix_e — 从矩阵中提取元素(已弃用的别名)。

igraph_real_t igraph_matrix_e(const igraph_matrix_t *m,
                                igraph_integer_t row, igraph_integer_t col);

警告

自 0.10.0 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_matrix_get()

3.16.3. igraph_matrix_e_ptr — 指向矩阵元素的指针。

igraph_real_t* igraph_matrix_e_ptr(const igraph_matrix_t *m,
                                     igraph_integer_t row, igraph_integer_t col);

警告

自 0.10.0 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_matrix_get_ptr()

4. 稀疏矩阵

4.1.  关于稀疏矩阵

igraph_sparsemat_t 数据类型存储稀疏矩阵,即大多数元素为零的矩阵。

该数据类型本质上是对 Tim Davis 的 CXSparse 库中的某些函数的包装,请参阅 http://faculty.cse.tamu.edu/davis/suitesparse.html

矩阵可以两种格式存储:三元组和列压缩。三元组格式适用于稀疏矩阵初始化,因为很容易向其中添加新的(非零)元素。大多数计算都在列压缩格式的稀疏矩阵上完成,用户通过 igraph_sparsemat_compress() 将三元组矩阵转换为列压缩格式之后。

两种格式都是动态的,因为可以向其中添加新元素,这可能会导致分配更多内存。

行和列索引遵循 C 约定,并且从零开始。

示例 7.4.  文件 examples/simple/igraph_sparsemat.c

#include <igraph.h>

int main(void) {

    igraph_sparsemat_t A, B, C, D;
    igraph_t G, H;
    igraph_vector_t vect;
    igraph_integer_t i;

    /* Create, compress, destroy */
    igraph_sparsemat_init(&A, 100, 20, 50);
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_destroy(&A);

    /* Convert a ring graph to a matrix, print it, compress, print again */
#define VC 10
    igraph_sparsemat_init(&A, 1, 1, 0);
    igraph_ring(&G, VC, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
    igraph_get_adjacency_sparse(&G, &A, IGRAPH_GET_ADJACENCY_BOTH, NULL, IGRAPH_LOOPS_ONCE);
    igraph_destroy(&G);

    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_print(&B, stdout);

    /* Basic query, nrow, ncol, type, is_triplet, is_cc */
    if (igraph_sparsemat_nrow(&A) != VC ||
        igraph_sparsemat_ncol(&A) != VC ||
        igraph_sparsemat_nrow(&B) != VC ||
        igraph_sparsemat_ncol(&B) != VC) {
        return 1;
    }
    if (!igraph_sparsemat_is_triplet(&A)) {
        return 2;
    }
    if (!igraph_sparsemat_is_cc(&B))      {
        return 3;
    }
    if (igraph_sparsemat_type(&A) != IGRAPH_SPARSEMAT_TRIPLET) {
        return 4;
    }
    if (igraph_sparsemat_type(&B) != IGRAPH_SPARSEMAT_CC)      {
        return 5;
    }

    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);
#undef VC

    printf("------------------------\n");

    /* Create unit matrices */
    igraph_sparsemat_init_eye(&A, /*n=*/ 5, /*nzmax=*/ 5, /*value=*/ 1.0, /*compress=*/ 0);
    igraph_sparsemat_init_eye(&B, /*n=*/ 5, /*nzmax=*/ 5, /*value=*/ 1.0, /*compress=*/ 1);
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);

    printf("------------------------\n");

    /* Create diagonal matrices */
    igraph_vector_init(&vect, 5);
    for (i = 0; i < 5; i++) {
        VECTOR(vect)[i] = i;
    }
    igraph_sparsemat_init_diag(&A, /*nzmax=*/ 5, /*values=*/ &vect, /*compress=*/ 0);
    igraph_sparsemat_init_diag(&B, /*nzmax=*/ 5, /*values=*/ &vect, /*compress=*/ 1);
    igraph_vector_destroy(&vect);
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);

    printf("------------------------\n");

    /* Transpose matrices */
    igraph_sparsemat_init(&A, 1, 1, 0);
    igraph_kary_tree(&G, 10, /*children=*/ 2, IGRAPH_TREE_OUT);
    igraph_get_adjacency_sparse(&G, &A, IGRAPH_GET_ADJACENCY_BOTH, NULL, IGRAPH_LOOPS_ONCE);
    igraph_destroy(&G);
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_transpose(&B, &C);
    igraph_sparsemat_print(&C, stdout);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_destroy(&C);

    printf("------------------------\n");

    /* Add duplicate elements */
    igraph_sparsemat_init(&A, 10, 10, /*nzmax=*/ 20);
    for (i = 1; i < 10; i++) {
        igraph_sparsemat_entry(&A, 0, i, 1.0);
    }
    for (i = 1; i < 10; i++) {
        igraph_sparsemat_entry(&A, 0, i, 1.0);
    }
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_dupl(&B);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);

    printf("------------------------\n");

    /* Drop zero elements */
    igraph_sparsemat_init(&A, 10, 10, /*nzmax=*/ 20);
    igraph_sparsemat_entry(&A, 7, 3, 0.0);
    for (i = 1; i < 10; i++) {
        igraph_sparsemat_entry(&A, 0, i, 1.0);
        igraph_sparsemat_entry(&A, 0, i, 0.0);
    }
    igraph_sparsemat_entry(&A, 0, 0, 0.0);
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_dropzeros(&B);
    igraph_sparsemat_print(&B, stdout);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);

    printf("------------------------\n");

    /* Add two matrices */

    igraph_sparsemat_init(&A, 1, 1, 0);
    igraph_sparsemat_init(&B, 1, 1, 0);
    igraph_star(&G, 10, IGRAPH_STAR_OUT, /*center=*/ 0);
    igraph_ring(&H, 10, /*directed=*/ 0, /*mutual=*/ 0, /*circular=*/ 1);
    igraph_get_adjacency_sparse(&G, &A, IGRAPH_GET_ADJACENCY_BOTH, NULL, IGRAPH_LOOPS_ONCE);
    igraph_get_adjacency_sparse(&H, &B, IGRAPH_GET_ADJACENCY_BOTH, NULL, IGRAPH_LOOPS_ONCE);
    igraph_destroy(&G);
    igraph_destroy(&H);
    igraph_sparsemat_compress(&A, &C);
    igraph_sparsemat_compress(&B, &D);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_add(&C, &D, /*alpha=*/ 1.0, /*beta=*/ 2.0, &A);
    igraph_sparsemat_destroy(&C);
    igraph_sparsemat_destroy(&D);
    igraph_sparsemat_print(&A, stdout);
    igraph_sparsemat_destroy(&A);

    return 0;
}


示例 7.5.  文件 examples/simple/igraph_sparsemat3.c

#include <igraph.h>

void permute(const igraph_matrix_t *M,
            const igraph_vector_int_t *p,
            const igraph_vector_int_t *q,
            igraph_matrix_t *res) {

    igraph_integer_t nrow = igraph_vector_int_size(p);
    igraph_integer_t ncol = igraph_vector_int_size(q);
    igraph_integer_t i, j;

    igraph_matrix_resize(res, nrow, ncol);

    for (i = 0; i < nrow; i++) {
        for (j = 0; j < ncol; j++) {
            igraph_integer_t ii = VECTOR(*p)[i];
            igraph_integer_t jj = VECTOR(*q)[j];
            MATRIX(*res, i, j) = MATRIX(*M, ii, jj);
        }
    }
}

void permute_rows(const igraph_matrix_t *M,
                 const igraph_vector_int_t *p,
                 igraph_matrix_t *res) {

    igraph_integer_t nrow = igraph_vector_int_size(p);
    igraph_integer_t ncol = igraph_matrix_ncol(M);
    igraph_integer_t i, j;

    igraph_matrix_resize(res, nrow, ncol);

    for (i = 0; i < nrow; i++) {
        for (j = 0; j < ncol; j++) {
            igraph_integer_t ii = VECTOR(*p)[i];
            MATRIX(*res, i, j) = MATRIX(*M, ii, j);
        }
    }
}

void permute_cols(const igraph_matrix_t *M,
                 const igraph_vector_int_t *q,
                 igraph_matrix_t *res) {

    igraph_integer_t nrow = igraph_matrix_nrow(M);
    igraph_integer_t ncol = igraph_vector_int_size(q);
    igraph_integer_t i, j;

    igraph_matrix_resize(res, nrow, ncol);

    for (i = 0; i < nrow; i++) {
        for (j = 0; j < ncol; j++) {
            igraph_integer_t jj = VECTOR(*q)[j];
            MATRIX(*res, i, j) = MATRIX(*M, i, jj);
        }
    }
}

void random_permutation(igraph_vector_int_t *vec) {
    /* We just do size(vec) * 2 swaps */
    igraph_integer_t one, two, i, n = igraph_vector_int_size(vec);
    igraph_integer_t tmp;
    for (i = 0; i < 2 * n; i++) {
        one = RNG_INTEGER(0, n - 1);
        two = RNG_INTEGER(0, n - 1);
        tmp = VECTOR(*vec)[one];
        VECTOR(*vec)[one] = VECTOR(*vec)[two];
        VECTOR(*vec)[two] = tmp;
    }
}

igraph_bool_t check_same(const igraph_sparsemat_t *A,
                         const igraph_matrix_t *M) {
    igraph_matrix_t A_dense;
    igraph_bool_t result;

    igraph_matrix_init(&A_dense, 1, 1);
    igraph_sparsemat_as_matrix(&A_dense, A);
    result = igraph_matrix_all_e(&A_dense, M);
    igraph_matrix_destroy(&A_dense);

    return result;
}

int main(void) {

    igraph_sparsemat_t A, B;
    igraph_matrix_t M, N;
    igraph_vector_int_t p, q;
    igraph_integer_t i;

    RNG_BEGIN();

    /* Permutation of a matrix */

#define NROW 10
#define NCOL 5
#define EDGES NROW*NCOL/3
    igraph_matrix_init(&M, NROW, NCOL);
    igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, NROW - 1);
        igraph_integer_t c = RNG_INTEGER(0, NCOL - 1);
        igraph_real_t value = RNG_INTEGER(1, 5);
        MATRIX(M, r, c) = MATRIX(M, r, c) + value;
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);

    igraph_vector_int_init_range(&p, 0, NROW);
    igraph_vector_int_init_range(&q, 0, NCOL);

    /* Identity */

    igraph_matrix_init(&N, 0, 0);
    permute(&M, &p, &q, &N);

    igraph_sparsemat_permute(&B, &p, &q, &A);
    igraph_sparsemat_dupl(&A);

    if (! check_same(&A, &N)) {
        return 1;
    }

    /* Random permutation */
    random_permutation(&p);
    random_permutation(&q);

    permute(&M, &p, &q, &N);

    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_permute(&B, &p, &q, &A);
    igraph_sparsemat_dupl(&A);

    if (! check_same(&A, &N)) {
        return 2;
    }

    igraph_vector_int_destroy(&p);
    igraph_vector_int_destroy(&q);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);
    igraph_matrix_destroy(&M);
    igraph_matrix_destroy(&N);

#undef NROW
#undef NCOL
#undef EDGES

    /* Indexing */

#define NROW 10
#define NCOL 5
#define EDGES NROW*NCOL/3
#define I_NROW 6
#define I_NCOL 3
    igraph_matrix_init(&M, NROW, NCOL);
    igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, NROW - 1);
        igraph_integer_t c = RNG_INTEGER(0, NCOL - 1);
        igraph_real_t value = RNG_INTEGER(1, 5);
        MATRIX(M, r, c) = MATRIX(M, r, c) + value;
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);

    igraph_vector_int_init(&p, I_NROW);
    igraph_vector_int_init(&q, I_NCOL);

    for (i = 0; i < I_NROW; i++) {
        VECTOR(p)[i] = RNG_INTEGER(0, I_NROW - 1);
    }
    for (i = 0; i < I_NCOL; i++) {
        VECTOR(p)[i] = RNG_INTEGER(0, I_NCOL - 1);
    }

    igraph_matrix_init(&N, 0, 0);
    permute(&M, &p, &q, &N);

    igraph_sparsemat_index(&B, &p, &q, &A, 0);

    if (! check_same(&A, &N)) {
        return 3;
    }

    igraph_sparsemat_destroy(&A);

    /* Getting single elements with index() */

    igraph_vector_int_resize(&p, 1);
    igraph_vector_int_resize(&q, 1);

    for (i = 0; i < 100; i++) {
        igraph_real_t value;
        VECTOR(p)[0] = RNG_INTEGER(0, NROW - 1);
        VECTOR(q)[0] = RNG_INTEGER(0, NCOL - 1);
        igraph_sparsemat_index(&B, &p, &q, /*res=*/ 0, &value);
        if (value != MATRIX(M, VECTOR(p)[0], VECTOR(q)[0])) {
            return 4;
        }
    }

    /* Getting single elements with get() */

    igraph_vector_int_resize(&p, 1);
    igraph_vector_int_resize(&q, 1);

    for (i = 0; i < 100; i++) {
        igraph_integer_t row = RNG_INTEGER(0, NROW - 1);
        igraph_integer_t col = RNG_INTEGER(0, NCOL - 1);
        if (igraph_sparsemat_get(&B, row, col) != MATRIX(M, row, col)) {
            return 4;
        }
    }

    /* Getting submatrices with index() */

    for (i = 0; i < 100; i++) {
        igraph_real_t value;
        VECTOR(p)[0] = RNG_INTEGER(0, NROW - 1);
        VECTOR(q)[0] = RNG_INTEGER(0, NCOL - 1);
        igraph_sparsemat_index(&B, &p, &q, /*res=*/ &A, &value);
        igraph_sparsemat_destroy(&A);
        if (value != MATRIX(M, VECTOR(p)[0], VECTOR(q)[0])) {
            return 4;
        }
    }

    igraph_vector_int_destroy(&p);
    igraph_vector_int_destroy(&q);
    igraph_sparsemat_destroy(&B);
    igraph_matrix_destroy(&M);
    igraph_matrix_destroy(&N);

    /* Indexing only the rows or the columns */

    igraph_matrix_init(&M, NROW, NCOL);
    igraph_sparsemat_init(&A, NROW, NCOL, EDGES);
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, NROW - 1);
        igraph_integer_t c = RNG_INTEGER(0, NCOL - 1);
        igraph_real_t value = RNG_INTEGER(1, 5);
        MATRIX(M, r, c) = MATRIX(M, r, c) + value;
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);

    igraph_vector_int_init(&p, I_NROW);
    igraph_vector_int_init(&q, I_NCOL);

    for (i = 0; i < I_NROW; i++) {
        VECTOR(p)[i] = RNG_INTEGER(0, I_NROW - 1);
    }
    for (i = 0; i < I_NCOL; i++) {
        VECTOR(p)[i] = RNG_INTEGER(0, I_NCOL - 1);
    }

    igraph_matrix_init(&N, 0, 0);
    permute_rows(&M, &p, &N);

    igraph_sparsemat_index(&B, &p, 0, &A, 0);

    if (! check_same(&A, &N)) {
        return 5;
    }

    permute_cols(&M, &q, &N);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_index(&B, 0, &q, &A, 0);

    if (! check_same(&A, &N)) {
        return 6;
    }

    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);
    igraph_vector_int_destroy(&p);
    igraph_vector_int_destroy(&q);
    igraph_matrix_destroy(&M);
    igraph_matrix_destroy(&N);

    RNG_END();

    return 0;
}


示例 7.6.  文件 examples/simple/igraph_sparsemat4.c

#include <igraph.h>

igraph_bool_t check_solution(const igraph_sparsemat_t *A,
                             const igraph_vector_t *x,
                             const igraph_vector_t *b) {

    igraph_vector_t res;
    igraph_real_t min, max;
    igraph_bool_t success;
    igraph_sparsemat_iterator_t it;

    igraph_vector_init_copy(&res, b);

    igraph_sparsemat_iterator_init(&it, (igraph_sparsemat_t*) A);
    while (!igraph_sparsemat_iterator_end(&it)) {
        igraph_integer_t row = igraph_sparsemat_iterator_row(&it);
        igraph_integer_t col = igraph_sparsemat_iterator_col(&it);
        igraph_real_t value = igraph_sparsemat_iterator_get(&it);
        VECTOR(res)[row] -= VECTOR(*x)[col] * value;
        igraph_sparsemat_iterator_next(&it);
    }

    igraph_vector_minmax(&res, &min, &max);
    igraph_vector_destroy(&res);

    success = fabs(min) < 1e-12 && fabs(max) < 1e-12;

    if (!success) {
        printf("Incorrect solution.\n\n");
        printf("A =\n"); igraph_sparsemat_print(A, stdout); printf("\n");
        printf("x =\n"); igraph_vector_print(x); printf("\n");
        printf("b =\n"); igraph_vector_print(b); printf("\n");
        printf("difference between A*x and b =\n");
        igraph_vector_print(&res); printf("\n\n");
    }

    return success;
}

int main(void) {

    igraph_sparsemat_t A, B, C;
    igraph_vector_t b, x;
    igraph_integer_t i;

    RNG_BEGIN();

    /* lsolve */

#define DIM 10
#define EDGES (DIM*DIM/6)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t c = RNG_INTEGER(0, r);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_lsolve(&B, &b, &x);

    if (! check_solution(&B, &x, &b)) {
        return 1;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&B);

#undef DIM
#undef EDGES

    /* ltsolve */

#define DIM 10
#define EDGES (DIM*DIM/6)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t c = RNG_INTEGER(0, r);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_ltsolve(&B, &b, &x);

    igraph_sparsemat_transpose(&B, &A);
    if (! check_solution(&A, &x, &b)) {
        return 2;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_destroy(&A);

#undef DIM
#undef EDGES

    /* usolve */

#define DIM 10
#define EDGES (DIM*DIM/6)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t c = RNG_INTEGER(0, r);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);
    igraph_sparsemat_transpose(&B, &A);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_usolve(&A, &b, &x);

    if (! check_solution(&A, &x, &b)) {
        return 3;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_destroy(&A);

#undef DIM
#undef EDGES

    /* utsolve */

#define DIM 10
#define EDGES (DIM*DIM/6)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t r = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t c = RNG_INTEGER(0, r);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, r, c, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);
    igraph_sparsemat_transpose(&B, &A);
    igraph_sparsemat_destroy(&B);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_utsolve(&A, &b, &x);

    igraph_sparsemat_transpose(&A, &B);
    if (! check_solution(&B, &x, &b)) {
        return 4;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&B);
    igraph_sparsemat_destroy(&A);

#undef DIM
#undef EDGES

    /* cholsol */
    /* We need a positive definite matrix, so we create a full-rank
       matrix first and then calculate A'A, which will be positive
       definite. */

#define DIM 10
#define EDGES (DIM*DIM/6)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t from = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t to = RNG_INTEGER(0, DIM - 1);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, from, to, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);
    igraph_sparsemat_transpose(&B, &A);
    igraph_sparsemat_multiply(&A, &B, &C);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_destroy(&B);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_cholsol(&C, &b, &x, /*order=*/ 0);

    if (! check_solution(&C, &x, &b)) {
        return 5;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&C);

#undef DIM
#undef EDGES

    /* lusol */

#define DIM 10
#define EDGES (DIM*DIM/4)
    igraph_sparsemat_init(&A, DIM, DIM, EDGES + DIM);
    for (i = 0; i < DIM; i++) {
        igraph_sparsemat_entry(&A, i, i, RNG_INTEGER(1, 3));
    }
    for (i = 0; i < EDGES; i++) {
        igraph_integer_t from = RNG_INTEGER(0, DIM - 1);
        igraph_integer_t to = RNG_INTEGER(0, DIM - 1);
        igraph_real_t value = RNG_INTEGER(1, 5);
        igraph_sparsemat_entry(&A, from, to, value);
    }
    igraph_sparsemat_compress(&A, &B);
    igraph_sparsemat_destroy(&A);
    igraph_sparsemat_dupl(&B);

    igraph_vector_init(&b, DIM);
    for (i = 0; i < DIM; i++) {
        VECTOR(b)[i] = RNG_INTEGER(1, 10);
    }

    igraph_vector_init(&x, DIM);
    igraph_sparsemat_lusol(&B, &b, &x, /*order=*/ 0, /*tol=*/ 1e-10);

    if (! check_solution(&B, &x, &b)) {
        return 6;
    }

    igraph_vector_destroy(&b);
    igraph_vector_destroy(&x);
    igraph_sparsemat_destroy(&B);

#undef DIM
#undef EDGES

    RNG_END();

    return 0;
}


示例 7.7.  文件 examples/simple/igraph_sparsemat6.c

#include <igraph.h>

int main(void) {
    igraph_matrix_t mat, mat2, mat3;
    igraph_sparsemat_t spmat, spmat2;

    igraph_rng_seed(igraph_rng_default(), 42);

#define NROW 10
#define NCOL 7
#define NUM_NONZEROS 15

    igraph_matrix_init(&mat, NROW, NCOL);
    for (igraph_integer_t i = 0; i < NUM_NONZEROS; i++) {
        igraph_integer_t r = igraph_rng_get_integer(igraph_rng_default(), 0, NROW - 1);
        igraph_integer_t c = igraph_rng_get_integer(igraph_rng_default(), 0, NCOL - 1);
        igraph_real_t val = igraph_rng_get_integer(igraph_rng_default(), 1, 10);
        MATRIX(mat, r, c) = val;
    }

    igraph_matrix_as_sparsemat(&spmat, &mat, /*tol=*/ 1e-14);
    igraph_matrix_init(&mat2, 0, 0);
    igraph_sparsemat_as_matrix(&mat2, &spmat);
    if (!igraph_matrix_all_e(&mat, &mat2)) {
        return 1;
    }

    igraph_sparsemat_compress(&spmat, &spmat2);
    igraph_matrix_init(&mat3, 0, 0);
    igraph_sparsemat_as_matrix(&mat3, &spmat2);
    if (!igraph_matrix_all_e(&mat, &mat3)) {
        return 2;
    }

    igraph_matrix_destroy(&mat);
    igraph_matrix_destroy(&mat2);
    igraph_matrix_destroy(&mat3);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);

    return 0;
}


示例 7.8.  文件 examples/simple/igraph_sparsemat7.c

#include <igraph.h>

#define DIM1 10
#define DIM2 5

#define RANDINT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))

int main(void) {
    igraph_matrix_t mat;
    igraph_sparsemat_t spmat, spmat2;
    igraph_real_t m1, m2;

    igraph_rng_seed(igraph_rng_default(), 42);

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    igraph_sparsemat_entry(&spmat, 1, 2, -1.0);
    igraph_sparsemat_entry(&spmat, 3, 2, 10.0);
    for (int i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, RANDINT(DIM1 - 1), RANDINT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_entry(&spmat, 1, 2, -1.0);
    igraph_sparsemat_entry(&spmat, 3, 2, 10.0);

    igraph_sparsemat_compress(&spmat, &spmat2);
    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat2);
    m1 = igraph_sparsemat_min(&spmat2);
    m2 = igraph_matrix_min(&mat);
    if (m1 != m2) {
        printf("%f %f\n", m1, m2);
        return 1;
    }
    m1 = igraph_sparsemat_max(&spmat2);
    m2 = igraph_matrix_max(&mat);
    if (m1 != m2) {
        printf("%f %f\n", m1, m2);
        return 2;
    }

    igraph_sparsemat_minmax(&spmat2, &m1, &m2);
    if (m1 != igraph_matrix_min(&mat)) {
        return 3;
    }
    if (m2 != igraph_matrix_max(&mat)) {
        return 4;
    }

    igraph_matrix_destroy(&mat);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);

    return 0;
}


示例 7.9.  文件 examples/simple/igraph_sparsemat8.c

#include <igraph.h>

#define DIM1 10
#define DIM2 5

#define INT(a) (igraph_rng_get_integer(igraph_rng_default(), 0, (a)))

int main(void) {
    igraph_matrix_t mat, mat2;
    igraph_sparsemat_t spmat, spmat2;
    igraph_integer_t i, j, nz1, nz2;
    igraph_vector_t sums1, sums2;


    igraph_rng_seed(igraph_rng_default(), 42);

    /* COPY */

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    for (i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, INT(DIM1 - 1), INT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_init_copy(&spmat2, &spmat);

    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat);
    igraph_matrix_init(&mat2, 0, 0);
    igraph_sparsemat_as_matrix(&mat2, &spmat2);
    if (!igraph_matrix_all_e(&mat, &mat2)) {
        return 1;
    }

    igraph_matrix_destroy(&mat2);
    igraph_sparsemat_destroy(&spmat2);

    igraph_sparsemat_compress(&spmat, &spmat2);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_init_copy(&spmat, &spmat2);

    igraph_matrix_init(&mat2, 0, 0);
    igraph_sparsemat_as_matrix(&mat2, &spmat);
    if (!igraph_matrix_all_e(&mat, &mat2)) {
        return 2;
    }

    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);
    igraph_matrix_destroy(&mat);
    igraph_matrix_destroy(&mat2);

    /* COLSUMS, ROWSUMS */

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    for (i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, INT(DIM1 - 1), INT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_compress(&spmat, &spmat2);

    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat);
    igraph_vector_init(&sums1, 0);
    igraph_vector_init(&sums2, 0);
    igraph_sparsemat_colsums(&spmat, &sums1);
    igraph_matrix_colsum(&mat, &sums2);
    if (!igraph_vector_all_e(&sums1, &sums2)) {
        return 3;
    }
    igraph_sparsemat_colsums(&spmat2, &sums1);
    if (!igraph_vector_all_e(&sums1, &sums2)) {
        return 4;
    }

    igraph_sparsemat_rowsums(&spmat, &sums1);
    igraph_matrix_rowsum(&mat, &sums2);
    if (!igraph_vector_all_e(&sums1, &sums2)) {
        return 5;
    }
    igraph_sparsemat_rowsums(&spmat2, &sums1);
    if (!igraph_vector_all_e(&sums1, &sums2)) {
        return 6;
    }

    igraph_matrix_destroy(&mat);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);
    igraph_vector_destroy(&sums1);
    igraph_vector_destroy(&sums2);

    /* COUNT_NONZERO, COUNT_NONZEROTOL */

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    igraph_sparsemat_entry(&spmat, 1, 2, 1.0);
    igraph_sparsemat_entry(&spmat, 1, 2, 1.0);
    igraph_sparsemat_entry(&spmat, 1, 3, 1e-12);
    for (i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, INT(DIM1 - 1), INT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_compress(&spmat, &spmat2);

    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat2);

    nz1 = igraph_sparsemat_count_nonzero(&spmat2);
    for (nz2 = 0, i = 0; i < igraph_matrix_nrow(&mat); i++) {
        for (j = 0; j < igraph_matrix_ncol(&mat); j++) {
            if (MATRIX(mat, i, j) != 0) {
                nz2++;
            }
        }
    }
    if (nz1 != nz2) {
        printf("%" IGRAPH_PRId " %" IGRAPH_PRId "\n", nz1, nz2);
        return 7;
    }

    nz1 = igraph_sparsemat_count_nonzerotol(&spmat2, 1e-10);
    for (nz2 = 0, i = 0; i < igraph_matrix_nrow(&mat); i++) {
        for (j = 0; j < igraph_matrix_ncol(&mat); j++) {
            if (fabs(MATRIX(mat, i, j)) >= 1e-10) {
                nz2++;
            }
        }
    }
    if (nz1 != nz2) {
        printf("%" IGRAPH_PRId " %" IGRAPH_PRId "\n", nz1, nz2);
        return 8;
    }

    igraph_matrix_destroy(&mat);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);

    /* SCALE */

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    for (i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, INT(DIM1 - 1), INT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_compress(&spmat, &spmat2);

    igraph_sparsemat_scale(&spmat, 2.0);
    igraph_sparsemat_scale(&spmat2, 2.0);
    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat);
    igraph_matrix_init(&mat2, 0, 0);
    igraph_sparsemat_as_matrix(&mat2, &spmat2);
    igraph_matrix_scale(&mat, 1.0 / 2.0);
    igraph_matrix_scale(&mat2, 1.0 / 2.0);
    if (!igraph_matrix_all_e(&mat, &mat2)) {
        return 9;
    }

    igraph_matrix_destroy(&mat);
    igraph_matrix_destroy(&mat2);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);

    /* ADDROWS, ADDCOLS */

    igraph_sparsemat_init(&spmat, DIM1, DIM2, 20);
    for (i = 0; i < 10; i++) {
        igraph_sparsemat_entry(&spmat, INT(DIM1 - 1), INT(DIM2 - 1), 1.0);
    }
    igraph_sparsemat_compress(&spmat, &spmat2);

    igraph_sparsemat_add_rows(&spmat, 3);
    igraph_sparsemat_add_cols(&spmat, 2);

    igraph_sparsemat_add_rows(&spmat2, 3);
    igraph_sparsemat_add_cols(&spmat2, 2);

    igraph_matrix_init(&mat, 0, 0);
    igraph_sparsemat_as_matrix(&mat, &spmat);
    igraph_matrix_init(&mat2, 0, 0);
    igraph_sparsemat_as_matrix(&mat2, &spmat2);
    if (!igraph_matrix_all_e(&mat, &mat2)) {
        return 10;
    }

    igraph_matrix_destroy(&mat);
    igraph_matrix_destroy(&mat2);
    igraph_sparsemat_destroy(&spmat);
    igraph_sparsemat_destroy(&spmat2);

    return 0;
}


4.2. 创建稀疏矩阵对象

4.2.1. igraph_sparsemat_init — 初始化三元组格式的稀疏矩阵。

igraph_error_t igraph_sparsemat_init(igraph_sparsemat_t *A, igraph_integer_t rows,
        igraph_integer_t cols, igraph_integer_t nzmax);

这是创建稀疏矩阵的最常见方法,以及 igraph_sparsemat_entry() 函数,该函数可用于逐个添加非零元素。完成后,用户可以调用 igraph_sparsemat_compress() 将矩阵转换为列压缩格式,以便对其进行计算。

用户必须在矩阵上调用 igraph_sparsemat_destroy() 以释放内存,一旦不再需要该矩阵。

参数: 

A:

指向尚未初始化的稀疏矩阵的指针。

rows:

矩阵中的行数。

cols:

列数。

nzmax:

矩阵中非零元素的最大数量。正确获得此值不是强制性的,但对于分配适当数量的内存很有用。

返回值: 

错误代码。

时间复杂度:待定。

4.2.2. igraph_sparsemat_init_copy — 复制稀疏矩阵。

igraph_error_t igraph_sparsemat_init_copy(
    igraph_sparsemat_t *to, const igraph_sparsemat_t *from
);

通过复制另一个稀疏矩阵来创建稀疏矩阵对象。源矩阵可以是三元组格式或列压缩格式。

将为复制矩阵分配与原始矩阵当前完全相同的内存量。

参数: 

:

指向未初始化的稀疏矩阵的指针,副本将在此处创建。

:

要复制的稀疏矩阵。

返回值: 

错误代码。

时间复杂度:O(n+nzmax),列数加上非零元素的最大数量。

4.2.3. igraph_sparsemat_init_diag — 创建稀疏对角矩阵。

igraph_error_t igraph_sparsemat_init_diag(
    igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values,
    igraph_bool_t compress
);

参数: 

A:

一个未初始化的稀疏矩阵,结果存储在此处。

nzmax:

非零元素的最大数量,这实质上给出了将为矩阵元素分配的内存量。

values:

要在对角线上存储的值,矩阵的大小由该向量的长度定义。

compress:

是否创建列压缩矩阵。如果为 false,则创建三元组矩阵。

返回值: 

错误代码。

时间复杂度:O(n),对角向量的长度。

4.2.4. igraph_sparsemat_init_eye — 创建稀疏单位矩阵。

igraph_error_t igraph_sparsemat_init_eye(
    igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax,
    igraph_real_t value, igraph_bool_t compress
);

参数: 

A:

一个未初始化的稀疏矩阵,结果存储在此处。

n:

矩阵中的行数和列数。

nzmax:

非零元素的最大数量,这实质上给出了将为矩阵元素分配的内存量。

:

要在对角线上存储的值。

compress:

是否创建列压缩矩阵。如果为 false,则创建三元组矩阵。

返回值: 

错误代码。

时间复杂度:O(n)。

4.2.5. igraph_sparsemat_realloc — 为稀疏矩阵分配更多(或更少)内存。

igraph_error_t igraph_sparsemat_realloc(igraph_sparsemat_t *A, igraph_integer_t nzmax);

稀疏矩阵会自动分配更多内存,根据需要。要控制内存分配,用户可以调用此函数,为给定数量的非零元素分配内存。

参数: 

A:

稀疏矩阵,可以是三元组格式或列压缩格式。

nzmax:

非零元素的新最大数量。

返回值: 

错误代码。

时间复杂度:待定。

4.2.6. igraph_sparsemat_destroy — 释放稀疏矩阵使用的内存。

void igraph_sparsemat_destroy(igraph_sparsemat_t *A);

一旦销毁,必须再次初始化稀疏矩阵,然后才能对其调用任何其他操作。

参数: 

A:

要销毁的稀疏矩阵。

时间复杂度:O(1)。

4.2.7. igraph_sparsemat_view — 初始化稀疏矩阵并设置所有参数。

igraph_error_t igraph_sparsemat_view(igraph_sparsemat_t *A, igraph_integer_t nzmax, igraph_integer_t m, igraph_integer_t n,
                          igraph_integer_t *p, igraph_integer_t *i, igraph_real_t *x, igraph_integer_t nz);

此函数可用于临时处理现有的稀疏矩阵数据,通常由另一个软件库创建,作为 igraph_sparsemat_t 对象,从而避免不必要的复制。它支持以压缩稀疏列格式或 (i, j, x) 三元组格式存储的数据,其中 ij 是非零元素的矩阵索引,x 是其值。

压缩稀疏列(或行)格式通常用于表示稀疏矩阵数据。它由三个向量组成,p 列指针,i 行索引和 x 值。p[k] 是矩阵列 k-1 和更低列中非零元素的数量。p[0] 始终为零,p[n] 始终为矩阵中非零元素的总数。i[l] 是第 l 个存储元素的行索引,而 x[l] 是其值。如果显式存储索引为 (j, k) 的矩阵元素,则它必须位于 ix 向量中的位置 p[k]p[k+1] - 1(包括)之间。

不要对使用此函数创建的稀疏矩阵调用 igraph_sparsemat_destroy()。相反,必须在 Acs 字段上调用 igraph_free() 以释放此函数分配的存储空间。

警告:使用此函数创建的矩阵不得与可能重新分配底层存储的函数一起使用,例如 igraph_sparsemat_entry()

参数: 

A:

未初始化的稀疏矩阵。

nzmax:

条目的最大数量,通常是条目的实际数量。

m:

矩阵行数。

n:

矩阵列数。

p:

对于压缩矩阵,这是列指针向量,并且大小必须为 n+1。对于三元组格式矩阵,它是列索引向量,并且大小必须为 nzmax

i:

行向量。这应包含 x 中元素的行索引。它的大小必须为 nzmax

x:

稀疏矩阵的非零元素的值。它的大小必须为 nzmax

nz:

对于压缩矩阵,它必须为 -1。对于三元组格式矩阵,它必须包含条目的数量。

返回值: 

错误代码。

时间复杂度:O(1)。

4.3. 查询稀疏矩阵的属性

4.3.1. igraph_sparsemat_index — 提取子矩阵或单个元素。

igraph_error_t igraph_sparsemat_index(const igraph_sparsemat_t *A,
                           const igraph_vector_int_t *p,
                           const igraph_vector_int_t *q,
                           igraph_sparsemat_t *res,
                           igraph_real_t *constres);

此函数索引到稀疏矩阵中。它有两个目的。首先,它可以从稀疏矩阵中提取子矩阵。其次,作为一种特殊情况,它可以从稀疏矩阵中提取单个元素。

参数: 

A:

输入矩阵,它必须是列压缩格式。

p:

一个整数向量或一个空指针。选定的行索引或索引。空指针选择所有行。

q:

一个整数向量或一个空指针。选定的列索引或索引。空指针选择所有列。

res:

指向未初始化的稀疏矩阵的指针,或一个空指针。如果不是空指针,则选定的子矩阵将存储在此处。

constres:

指向实变量的指针或一个空指针。如果不是空指针,则选定子矩阵中的第一个非零元素将存储在此处(如果存在)。否则,将在此处存储零。如果有人想从矩阵中选择单个条目,则此行为很方便。

返回值: 

错误代码。

时间复杂度:待定。

4.3.2. igraph_sparsemat_nrow — 行数。

igraph_integer_t igraph_sparsemat_nrow(const igraph_sparsemat_t *A);

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

返回值: 

A 矩阵中的行数。

时间复杂度:O(1)。

4.3.3. igraph_sparsemat_ncol — 列数。

igraph_integer_t igraph_sparsemat_ncol(const igraph_sparsemat_t *A);

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

返回值: 

A 矩阵中的列数。

时间复杂度:O(1)。

4.3.4. igraph_sparsemat_type — 稀疏矩阵的类型(三元组或列压缩)。

igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A);

指示稀疏矩阵是以三元组格式还是以列压缩格式存储。

参数: 

A:

输入矩阵。

返回值: 

要么是 IGRAPH_SPARSEMAT_CC,要么是 IGRAPH_SPARSEMAT_TRIPLET

时间复杂度:O(1)。

4.3.5. igraph_sparsemat_is_triplet — 此稀疏矩阵是否为三元组格式?

igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A);

确定稀疏矩阵是否为三元组格式。

参数: 

A:

输入矩阵。

返回值: 

如果输入矩阵为三元组格式,则为 1,否则为零。

时间复杂度:O(1)。

4.3.6. igraph_sparsemat_is_cc — 此稀疏矩阵是否为列压缩格式?

igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A);

确定稀疏矩阵是否为列压缩格式。

参数: 

A:

输入矩阵。

返回值: 

如果输入矩阵为列压缩格式,则为 1,否则为零。

时间复杂度:O(1)。

4.3.7. igraph_sparsemat_is_symmetric — 返回稀疏矩阵是否对称。

igraph_error_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A, igraph_bool_t *result);

参数: 

A:

输入矩阵

结果:

指向 igraph_bool_t 的指针;结果在此处提供。

返回值: 

错误代码。

4.3.8. igraph_sparsemat_get — 从稀疏矩阵返回单个元素的值。

igraph_real_t igraph_sparsemat_get(
    const igraph_sparsemat_t *A, igraph_integer_t row, igraph_integer_t col
);

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

row:

行索引

col:

列索引

返回值: 

矩阵中具有给定行和列索引的单元格的值;如果索引超出范围,则为零。

时间复杂度:待定。

4.3.9. igraph_sparsemat_getelements — 返回稀疏矩阵的所有元素。

igraph_error_t igraph_sparsemat_getelements(const igraph_sparsemat_t *A,
                                 igraph_vector_int_t *i,
                                 igraph_vector_int_t *j,
                                 igraph_vector_t *x);

此函数将以三个向量返回稀疏矩阵的元素。两个向量将指示元素的位置,一个向量将指定元素本身。

参数: 

A:

三元组或压缩形式的稀疏矩阵。

i:

一个初始化的整数向量。这将存储返回元素的行。

j:

一个初始化的整数向量。对于三元组矩阵,这将存储返回元素的列。对于压缩矩阵,如果列索引为 k,则 j[k]x 中第 k 列开始的索引,并且 j 的最后一个元素是元素的总数。因此,第 k 列中元素的总数为 j[k+1] - j[k]。例如,如果第一列中有一个元素,第二列中有五个元素,则 j 将设置为 {0, 1, 6}

x:

一个初始化的向量。元素将放置在此处。

返回值: 

错误代码。

时间复杂度:O(n),稀疏矩阵中存储元素的数量。

4.3.10. igraph_sparsemat_getelements_sorted — 返回稀疏矩阵的所有元素,按行和列索引排序。

igraph_error_t igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A,
                                        igraph_vector_int_t *i,
                                        igraph_vector_int_t *j,
                                        igraph_vector_t *x);

此函数将对稀疏矩阵进行排序,并在三个向量中返回元素。两个向量将指示元素的位置,一个向量将指定元素本身。

排序是基于元素的 索引 而不是它们的数值完成的。返回的条目将按列索引排序;然后,同一列中的条目按行索引排序。

参数: 

A:

三元组或压缩形式的稀疏矩阵。

i:

一个初始化的整数向量。这将存储返回元素的行。

j:

一个初始化的整数向量。对于三元组矩阵,这将存储返回元素的列。对于压缩矩阵,如果列索引为 k,则 j[k]x 中第 k 列开始的索引,并且 j 的最后一个元素是元素的总数。因此,第 k 列中元素的总数为 j[k+1] - j[k]。例如,如果第一列中有一个元素,第二列中有五个元素,则 j 将设置为 {0, 1, 6}

x:

一个初始化的向量。元素将放置在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.3.11. igraph_sparsemat_min — 稀疏矩阵的最小值。

igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A);

参数: 

A:

输入矩阵,列压缩。

返回值: 

输入矩阵中的最小值,如果矩阵具有零元素,则为 IGRAPH_POSINFINITY

时间复杂度:待定。

4.3.12. igraph_sparsemat_max — 稀疏矩阵的最大值。

igraph_real_t igraph_sparsemat_max(igraph_sparsemat_t *A);

参数: 

A:

输入矩阵,列压缩。

返回值: 

输入矩阵中的最大值,如果矩阵具有零元素,则为 IGRAPH_NEGINFINITY

时间复杂度:待定。

4.3.13. igraph_sparsemat_minmax — 稀疏矩阵的最小值和最大值。

igraph_error_t igraph_sparsemat_minmax(igraph_sparsemat_t *A,
                            igraph_real_t *min, igraph_real_t *max);

参数: 

A:

输入矩阵,列压缩。

min:

输入矩阵中的最小值存储在此处,如果矩阵具有零元素,则为 IGRAPH_POSINFINITY

max:

输入矩阵中的最大值存储在此处,如果矩阵具有零元素,则为 IGRAPH_NEGINFINITY

返回值: 

错误代码。

时间复杂度:待定。

4.3.14. igraph_sparsemat_count_nonzero — 计数稀疏矩阵的非零元素。

igraph_integer_t igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A);

参数: 

A:

输入矩阵,列压缩。

返回值: 

错误代码。

时间复杂度:待定。

4.3.15. igraph_sparsemat_count_nonzerotol — 计数稀疏矩阵的非零元素,忽略接近零的元素。

igraph_integer_t igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A,
        igraph_real_t tol);

计算比 tol 更接近零的矩阵条目的数量。

参数: 

The:

输入矩阵,列压缩。

The:

零比较的容差。

返回值: 

错误代码。

时间复杂度:待定。

4.3.16. igraph_sparsemat_rowsums — 按行求和。

igraph_error_t igraph_sparsemat_rowsums(const igraph_sparsemat_t *A,
                             igraph_vector_t *res);

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

res:

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

返回值: 

错误代码。

时间复杂度:O(nz),非零元素的数量。

4.3.17. igraph_sparsemat_colsums — 按列求和。

igraph_error_t igraph_sparsemat_colsums(const igraph_sparsemat_t *A,
                             igraph_vector_t *res);

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

res:

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

返回值: 

错误代码。

时间复杂度:对于三元组矩阵为 O(nz),对于列压缩矩阵为 O(nz+n),nz 是非零元素的数量,n 是列数。

4.3.18. igraph_sparsemat_nonzero_storage — 返回稀疏矩阵的存储条目数。

igraph_integer_t igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A);

此函数将返回稀疏矩阵的存储条目数。这些条目可能为零,并且多个条目可能位于同一位置。使用 igraph_sparsemat_dupl() 对重复条目求和,并使用 igraph_sparsemat_dropzeros() 删除零。

参数: 

A:

三元组或压缩形式的稀疏矩阵。

返回值: 

存储条目的数量。

时间复杂度:O(1)。

4.4. 稀疏矩阵上的运算

4.4.1. igraph_sparsemat_entry — 向稀疏矩阵添加元素。

igraph_error_t igraph_sparsemat_entry(igraph_sparsemat_t *A,
        igraph_integer_t row, igraph_integer_t col, igraph_real_t elem);

在用 igraph_sparsemat_init() 初始化稀疏矩阵后,可以使用此函数将条目添加到稀疏矩阵中。如果在同一位置添加多个条目,则将保存所有条目,并且结果值是该位置中所有条目的总和。

参数: 

A:

输入矩阵,它必须是三元组格式。

row:

要添加的条目的行索引。

col:

要添加的条目的列索引。

elem:

条目的值。

返回值: 

错误代码。

时间复杂度:平均 O(1)。

4.4.2. igraph_sparsemat_fkeep — 过滤稀疏矩阵的元素。

igraph_error_t igraph_sparsemat_fkeep(
    igraph_sparsemat_t *A,
    igraph_integer_t (*fkeep)(igraph_integer_t, igraph_integer_t, igraph_real_t, void*),
    void *other
);

此函数可用于过滤稀疏矩阵的(非零)元素。对于所有条目,它都会调用提供的函数,并根据返回值保留或删除矩阵中的元素。

参数: 

A:

输入矩阵,列压缩格式。

fkeep:

筛选函数。它必须接受四个参数:第一个是 igraph_integer_t,条目的行索引;第二个是另一个 igraph_integer_t,列索引;第三个是 igraph_real_t,条目的值;第四个元素是一个 void 指针,other 参数将传递到此处。该函数必须返回一个 int。如果为零,则删除该条目,否则保留该条目。

other:

一个 void 指针,将传递给筛选函数。

返回值: 

错误代码。

时间复杂度:待定。

4.4.3. igraph_sparsemat_dropzeros — 从稀疏矩阵中删除零元素。

igraph_error_t igraph_sparsemat_dropzeros(igraph_sparsemat_t *A);

由于矩阵运算,稀疏矩阵中的某些条目可能为零。此函数删除这些条目。

参数: 

A:

输入矩阵,它必须是列压缩格式。

返回值: 

错误代码。

时间复杂度:待定。

4.4.4. igraph_sparsemat_droptol — 从稀疏矩阵中删除几乎为零的元素。

igraph_error_t igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol);

此函数类似于 igraph_sparsemat_dropzeros(),但它也会删除比给定的容差阈值更接近零的条目。

参数: 

A:

输入矩阵,它必须是列压缩格式。

tol:

实数,给出容差阈值。

返回值: 

错误代码。

时间复杂度:待定。

4.4.5. igraph_sparsemat_scale — 缩放稀疏矩阵。

igraph_error_t igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by);

将稀疏矩阵的所有元素乘以给定的因子。

参数: 

A:

输入矩阵。

by:

比例因子。

返回值: 

错误代码。

时间复杂度:O(nz),矩阵中非零元素的数量。

4.4.6. igraph_sparsemat_permute — 排列稀疏矩阵的行和列。

igraph_error_t igraph_sparsemat_permute(const igraph_sparsemat_t *A,
                                        const igraph_vector_int_t *p,
                                        const igraph_vector_int_t *q,
                                        igraph_sparsemat_t *res);

参数: 

A:

输入矩阵,它必须是列压缩格式。

p:

整数向量,给出行的排列。

q:

整数向量,列的排列。

res:

指向未初始化的稀疏矩阵的指针,结果存储在此处。

返回值: 

错误代码。

时间复杂度:O(m+n+nz),行数加上列数加上矩阵中非零元素的数量。

4.4.7. igraph_sparsemat_transpose — 转置稀疏矩阵。

igraph_error_t igraph_sparsemat_transpose(
    const igraph_sparsemat_t *A, igraph_sparsemat_t *res
);

参数: 

A:

输入矩阵,列压缩格式或三元组格式。

res:

指向未初始化的稀疏矩阵的指针,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.4.8. igraph_sparsemat_add — 两个稀疏矩阵的和。

igraph_error_t igraph_sparsemat_add(const igraph_sparsemat_t *A,
                         const igraph_sparsemat_t *B,
                         igraph_real_t alpha,
                         igraph_real_t beta,
                         igraph_sparsemat_t *res);

参数: 

A:

第一个输入矩阵,列压缩格式。

B:

第二个输入矩阵,列压缩格式。

alpha:

实数值,A 在加法之前乘以 alpha

beta:

实数值,B 在加法之前乘以 beta

res:

指向未初始化的稀疏矩阵的指针,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.4.9. igraph_sparsemat_multiply — 矩阵乘法。

igraph_error_t igraph_sparsemat_multiply(const igraph_sparsemat_t *A,
                              const igraph_sparsemat_t *B,
                              igraph_sparsemat_t *res);

乘以两个稀疏矩阵。

参数: 

A:

第一个输入矩阵(左侧),列压缩格式。

B:

第二个输入矩阵(右侧),列压缩格式。

res:

指向未初始化的稀疏矩阵的指针,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.4.10. igraph_sparsemat_gaxpy — 矩阵-向量乘积,添加到另一个向量。

igraph_error_t igraph_sparsemat_gaxpy(const igraph_sparsemat_t *A,
                           const igraph_vector_t *x,
                           igraph_vector_t *res);

参数: 

A:

输入矩阵,列压缩格式。

x:

输入向量,其大小必须与 A 中的列数匹配。

res:

此向量将添加到矩阵-向量乘积中,并被结果覆盖。

返回值: 

错误代码。

时间复杂度:待定。

4.4.11. igraph_sparsemat_add_rows — 向稀疏矩阵添加行。

igraph_error_t igraph_sparsemat_add_rows(igraph_sparsemat_t *A, igraph_integer_t n);

当前矩阵元素将被保留,并且新行中的所有元素都为零。

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

n:

要添加的行数。

返回值: 

错误代码。

时间复杂度:O(1)。

4.4.12. igraph_sparsemat_add_cols — 向稀疏矩阵添加列。

igraph_error_t igraph_sparsemat_add_cols(igraph_sparsemat_t *A, igraph_integer_t n);

当前矩阵元素将被保留,并且新列中的所有元素都为零。

参数: 

A:

输入矩阵,三元组格式或列压缩格式。

n:

要添加的列数。

返回值: 

错误代码。

时间复杂度:待定。

4.4.13. igraph_sparsemat_resize — 调整稀疏矩阵的大小并清除所有元素。

igraph_error_t igraph_sparsemat_resize(igraph_sparsemat_t *A, igraph_integer_t nrow,
                            igraph_integer_t ncol, igraph_integer_t nzmax);

此函数会调整稀疏矩阵的大小。调整大小后的稀疏矩阵将变为空,即使其中包含非零条目。

参数: 

A:

要调整大小的已初始化稀疏矩阵。

nrow:

新的行数。

ncol:

新的列数。

nzmax:

元素的新最大数量。

返回值: 

错误代码。

时间复杂度:O(nzmax),非零元素的最大数量。

4.4.14. igraph_sparsemat_sort — 按行和列索引对稀疏矩阵的所有元素进行排序。

igraph_error_t igraph_sparsemat_sort(const igraph_sparsemat_t *A,
                          igraph_sparsemat_t *sorted);

此函数将对稀疏矩阵的元素进行排序,以便迭代条目将返回按列索引排序的条目;然后,同一列中的元素按行索引排序。

参数: 

A:

三元组或压缩形式的稀疏矩阵。

sorted:

一个未初始化的稀疏矩阵;结果将返回到此处。如果输入为三元组格式,则结果将为三元组格式,否则将为压缩格式。请注意,当矩阵已经为压缩格式时,排序效率更高。

返回值: 

错误代码。

时间复杂度:TODO

4.5. 稀疏矩阵迭代器上的运算

4.5.1. igraph_sparsemat_iterator_init — 初始化稀疏矩阵迭代器。

igraph_error_t igraph_sparsemat_iterator_init(
    igraph_sparsemat_iterator_t *it, const igraph_sparsemat_t *sparsemat
);

参数: 

it:

指向未初始化的稀疏矩阵迭代器的指针。

sparsemat:

指向稀疏矩阵的指针。

返回值: 

错误代码。始终返回 IGRAPH_SUCCESS

时间复杂度:O(n),稀疏矩阵的列数。

4.5.2. igraph_sparsemat_iterator_reset — 将稀疏矩阵迭代器重置到第一个元素。

igraph_error_t igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

错误代码。始终返回 IGRAPH_SUCCESS

时间复杂度:O(n),稀疏矩阵的列数。

4.5.3. igraph_sparsemat_iterator_end — 查询迭代器是否已超过最后一个元素。

igraph_bool_t
igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

如果迭代器已超过最后一个元素,则为 true;如果它指向稀疏矩阵中的一个元素,则为 false。

时间复杂度:O(1)。

4.5.4. igraph_sparsemat_iterator_row — 返回迭代器所在的行。

igraph_integer_t igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

当前迭代器位置的元素的行。

时间复杂度:O(1)。

4.5.5. igraph_sparsemat_iterator_col — 返回迭代器所在的列。

igraph_integer_t igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

当前迭代器位置的元素的列。

时间复杂度:O(1)。

4.5.6. igraph_sparsemat_iterator_get — 返回当前迭代器位置的元素。

igraph_real_t
igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

当前迭代器位置的元素的值。

时间复杂度:O(1)。

4.5.7. igraph_sparsemat_iterator_next — 将稀疏矩阵迭代器移动到下一个元素。

igraph_integer_t igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

迭代器在元素向量中的位置。

时间复杂度:O(n),稀疏矩阵的列数。

4.5.8. igraph_sparsemat_iterator_idx — 返回稀疏矩阵迭代器的元素向量索引。

igraph_integer_t igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it);

参数: 

it:

指向稀疏矩阵迭代器的指针。

返回值: 

迭代器在元素向量中的位置。

时间复杂度:O(1)。

4.6. 更改内部表示的操作

4.6.1. igraph_sparsemat_compress — 将稀疏矩阵转换为列压缩格式。

igraph_error_t igraph_sparsemat_compress(const igraph_sparsemat_t *A,
                              igraph_sparsemat_t *res);

将稀疏矩阵从三元组格式转换为列压缩格式。几乎所有稀疏矩阵操作都要求矩阵采用列压缩格式。

参数: 

A:

输入矩阵,它必须是三元组格式。

res:

指向未初始化的稀疏矩阵对象的指针,A 的压缩版本存储在此处。

返回值: 

错误代码。

时间复杂度:O(nz),其中 nz 是非零元素的数量。

4.6.2. igraph_sparsemat_dupl — 从稀疏矩阵中删除重复元素。

igraph_error_t igraph_sparsemat_dupl(igraph_sparsemat_t *A);

列压缩稀疏矩阵可能会以多个部分存储单个矩阵条目。然后该条目是其所有部分的和。(某些函数创建的矩阵就是这样。)此函数消除了多个部分。

参数: 

A:

输入矩阵,列压缩格式。

返回值: 

错误代码。

时间复杂度:待定。

4.7. 分解和求解线性系统

4.7.1. igraph_sparsemat_symblu — 符号 LU 分解。

igraph_error_t igraph_sparsemat_symblu(igraph_integer_t order, const igraph_sparsemat_t *A,
                            igraph_sparsemat_symbolic_t *dis);

稀疏矩阵的 LU 分解涉及两个步骤,首先调用此函数,然后调用 igraph_sparsemat_lu()

参数: 

order:

要使用的排序:0 表示自然排序,1 表示 A+A' 的最小度排序,2 表示从 A 中删除密集行后 A'A 的最小度排序,3 表示 A'A 的最小度排序。

A:

输入矩阵,列压缩格式。

dis:

符号分析的结果存储在此处。一旦不再需要,必须通过调用 igraph_sparsemat_symbolic_destroy() 来销毁它。

返回值: 

错误代码。

时间复杂度:待定。

4.7.2. igraph_sparsemat_symbqr — 符号 QR 分解。

igraph_error_t igraph_sparsemat_symbqr(igraph_integer_t order, const igraph_sparsemat_t *A,
                            igraph_sparsemat_symbolic_t *dis);

稀疏矩阵的 QR 分解涉及两个步骤,首先调用此函数,然后调用 igraph_sparsemat_qr()

参数: 

order:

要使用的排序:0 表示自然排序,1 表示 A+A' 的最小度排序,2 表示从 A 中删除密集行后 A'A 的最小度排序,3 表示 A'A 的最小度排序。

A:

输入矩阵,列压缩格式。

dis:

符号分析的结果存储在此处。一旦不再需要,必须通过调用 igraph_sparsemat_symbolic_destroy() 来销毁它。

返回值: 

错误代码。

时间复杂度:待定。

4.7.3. igraph_sparsemat_lsolve — 求解下三角线性系统。

igraph_error_t igraph_sparsemat_lsolve(const igraph_sparsemat_t *L,
                            const igraph_vector_t *b,
                            igraph_vector_t *res);

求解 Lx=b 线性方程组,其中 L 系数矩阵是具有无零对角线的方阵且下三角。

参数: 

L:

输入矩阵,列压缩格式。

b:

线性系统的右侧。

res:

初始化的向量,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.7.4. igraph_sparsemat_ltsolve — 求解上三角线性系统。

igraph_error_t igraph_sparsemat_ltsolve(const igraph_sparsemat_t *L,
                             const igraph_vector_t *b,
                             igraph_vector_t *res);

求解 L'x=b 线性方程组,其中 L 矩阵是具有无零对角线的方阵且下三角。

参数: 

L:

输入矩阵,列压缩格式。

b:

线性系统的右侧。

res:

初始化的向量,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.7.5. igraph_sparsemat_usolve — 求解上三角线性系统。

igraph_error_t igraph_sparsemat_usolve(const igraph_sparsemat_t *U,
                            const igraph_vector_t *b,
                            igraph_vector_t *res);

求解 Ux=b 上三角系统。

参数: 

U:

输入矩阵,列压缩格式。

b:

线性系统的右侧。

res:

初始化的向量,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.7.6. igraph_sparsemat_utsolve — 求解下三角线性系统。

igraph_error_t igraph_sparsemat_utsolve(const igraph_sparsemat_t *U,
                             const igraph_vector_t *b,
                             igraph_vector_t *res);

这与 igraph_sparsemat_usolve() 相同,但求解的是 U'x=b,其中撇号表示转置。

参数: 

U:

输入矩阵,列压缩格式。

b:

线性系统的右侧。

res:

初始化的向量,结果存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.7.7. igraph_sparsemat_cholsol — 通过 Cholesky 分解求解对称线性系统。

igraph_error_t igraph_sparsemat_cholsol(const igraph_sparsemat_t *A,
                             const igraph_vector_t *b,
                             igraph_vector_t *res,
                             igraph_integer_t order);

求解 Ax=b,其中 A 是对称正定矩阵。

参数: 

A:

输入矩阵,列压缩格式。

v:

右手边。

res:

初始化的向量,结果存储在此处。

order:

一个整数,给出用于分解的排序方法。零是自然排序;如果它是一,则使用 A+A' 的填充减少最小度排序。

返回值: 

错误代码。

时间复杂度:待定。

4.7.8. igraph_sparsemat_lusol — 通过 LU 分解求解线性系统。

igraph_error_t igraph_sparsemat_lusol(const igraph_sparsemat_t *A,
                           const igraph_vector_t *b,
                           igraph_vector_t *res,
                           igraph_integer_t order,
                           igraph_real_t tol);

通过 A 的 LU 分解求解 Ax=b。

参数: 

A:

输入矩阵,列压缩格式。

b:

方程的右手边。

res:

初始化的向量,结果存储在此处。

order:

要使用的排序方法,零表示自然排序,一表示 A+A' 的填充减少最小度排序,二表示 A'*A 的排序,从 A 中删除密集行后。三表示 A'*A 的排序。

tol:

实数,用于数值 LU 分解的容差限制。

返回值: 

错误代码。

时间复杂度:待定。

4.7.9. igraph_sparsemat_lu — 稀疏矩阵的 LU 分解。

igraph_error_t igraph_sparsemat_lu(const igraph_sparsemat_t *A,
                        const igraph_sparsemat_symbolic_t *dis,
                        igraph_sparsemat_numeric_t *din, double tol);

执行矩阵的数值稀疏 LU 分解。

参数: 

A:

输入矩阵,列压缩格式。

dis:

LU 分解的符号分析,来自对 igraph_sparsemat_symblu() 函数的调用。

din:

数值分解,结果存储在此处。通过调用 igraph_sparsemat_luresol(),它可用于求解具有变化的右手边向量的线性系统。一旦不再需要,必须通过调用 igraph_sparsemat_symbolic_destroy() 来销毁它。

tol:

数值 LU 分解的容差。

返回值: 

错误代码。

时间复杂度:待定。

4.7.10. igraph_sparsemat_qr — 稀疏矩阵的 QR 分解。

igraph_error_t igraph_sparsemat_qr(const igraph_sparsemat_t *A,
                        const igraph_sparsemat_symbolic_t *dis,
                        igraph_sparsemat_numeric_t *din);

稀疏矩阵的数值 QR 分解。

参数: 

A:

输入矩阵,列压缩格式。

dis:

符号 QR 分析的结果,来自函数 igraph_sparsemat_symbqr()

din:

分解的结果存储在此处,通过使用 igraph_sparsemat_qrresol() 函数,它可用于求解具有相同系数矩阵和变化的右手边的许多线性系统。一旦不再需要,应该在其上调用 igraph_sparsemat_numeric_destroy() 以释放已分配的内存。

返回值: 

错误代码。

时间复杂度:待定。

4.7.11. igraph_sparsemat_luresol — 使用预计算的 LU 分解求解线性系统。

igraph_error_t igraph_sparsemat_luresol(const igraph_sparsemat_symbolic_t *dis,
                             const igraph_sparsemat_numeric_t *din,
                             const igraph_vector_t *b,
                             igraph_vector_t *res);

使用矩阵的 LU 分解来求解线性系统。

参数: 

dis:

系数矩阵的符号分析,igraph_sparsemat_symblu() 的结果。

din:

LU 分解,调用 igraph_sparsemat_lu() 的结果。

b:

一个向量,定义线性方程组的右手边。

res:

一个初始化的向量,线性系统的解存储在此处。

返回值: 

错误代码。

时间复杂度:待定。

4.7.12. igraph_sparsemat_qrresol — 使用预计算的 QR 分解求解线性系统。

igraph_error_t igraph_sparsemat_qrresol(const igraph_sparsemat_symbolic_t *dis,
                             const igraph_sparsemat_numeric_t *din,
                             const igraph_vector_t *b,
                             igraph_vector_t *res);

使用其系数矩阵的 QR 分解求解线性系统。

参数: 

dis:

系数矩阵的符号分析,igraph_sparsemat_symbqr() 的结果。

din:

系数矩阵的 QR 分解,igraph_sparsemat_qr() 的结果。

b:

向量,给出线性方程组的右手边。

res:

一个初始化的向量,解存储在此处。它会根据需要调整大小。

返回值: 

错误代码。

时间复杂度:待定。

4.7.13. igraph_sparsemat_symbolic_destroy — 在符号分解后释放内存。

void igraph_sparsemat_symbolic_destroy(igraph_sparsemat_symbolic_t *dis);

释放由 igraph_sparsemat_symbqr()igraph_sparsemat_symblu() 分配的内存。

参数: 

dis:

符号分析。

时间复杂度:O(1)。

4.7.14. igraph_sparsemat_numeric_destroy — 在数值分解后释放内存。

void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din);

释放由 igraph_sparsemat_qr()igraph_sparsemat_lu() 分配的内存。

参数: 

din:

LU 或 QR 分解。

时间复杂度:O(1)。

4.8. 特征值和特征向量

4.8.1. igraph_sparsemat_arpack_rssolve — 通过 ARPACK 获取对称稀疏矩阵的特征值和特征向量。

igraph_error_t igraph_sparsemat_arpack_rssolve(const igraph_sparsemat_t *A,
                                    igraph_arpack_options_t *options,
                                    igraph_arpack_storage_t *storage,
                                    igraph_vector_t *values,
                                    igraph_matrix_t *vectors,
                                    igraph_sparsemat_solve_t solvemethod);

参数: 

The:

输入矩阵,必须是列压缩的。

选项:

它传递给 igraph_arpack_rssolve()。在此处提供 NULL 以使用默认值。有关详细信息,请参阅 igraph_arpack_options_t。如果 mode 是 1,则 ARPACK 使用常规模式;如果 mode 是 3,则使用移位和求逆模式,并且 sigma 结构成员定义移位。

storage:

ARPACK 的存储。有关详细信息,请参阅 igraph_arpack_rssolve()igraph_arpack_storage_t

values:

一个初始化的向量或一个空指针,特征值存储在此处。

vectors:

一个初始化的矩阵或一个空指针,特征向量存储在此处的列中。

solvemethod:

求解线性系统的方法,如果 mode 是 3,即使用移位和求逆模式。可能的值

IGRAPH_SPARSEMAT_SOLVE_LU

线性系统使用 LU 分解求解。

IGRAPH_SPARSEMAT_SOLVE_QR

线性系统使用 QR 分解求解。

返回值: 

错误代码。

时间复杂度:待定。

4.8.2. igraph_sparsemat_arpack_rnsolve — 通过 ARPACK 获取非对称稀疏矩阵的特征值和特征向量。

igraph_error_t igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A,
                                    igraph_arpack_options_t *options,
                                    igraph_arpack_storage_t *storage,
                                    igraph_matrix_t *values,
                                    igraph_matrix_t *vectors);

非对称稀疏矩阵的特征值和/或特征向量。

参数: 

A:

输入矩阵,采用列压缩模式。

选项:

ARPACK 选项,它传递给 igraph_arpack_rnsolve()。在此处提供 NULL 以使用默认值。另请参阅 igraph_arpack_options_t 以获取详细信息。

storage:

ARPACK 的存储,这传递给 igraph_arpack_rnsolve()。有关详细信息,请参阅 igraph_arpack_storage_t

values:

一个初始化的矩阵或一个空指针。如果不是空指针,则特征值存储在此处,第一列是实部,第二列是虚部。

vectors:

一个初始化的矩阵或一个空指针。如果不是空指针,则特征向量存储在此处,请参阅 igraph_arpack_rnsolve() 以获取格式。

返回值: 

错误代码。

时间复杂度:待定。

4.9. 转换为其他数据类型

4.9.1. igraph_sparsemat — 从稀疏矩阵创建 igraph 图。

igraph_error_t igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,
                     igraph_bool_t directed);

为矩阵中的每个非零条目创建一个边。如果您有一个对称矩阵,并且想要创建一个无向图,请首先删除上对角线中的条目,或者在结果图上调用 igraph_simplify() 以消除多重边。

参数: 

:

指向未初始化的 igraph_t 对象的指针,图存储在此处。

A:

输入矩阵,三元组格式或列压缩格式。

有向:

是否创建有向图。

返回值: 

错误代码。

时间复杂度:待定。

4.9.2. igraph_matrix_as_sparsemat — 将密集矩阵转换为稀疏矩阵。

igraph_error_t igraph_matrix_as_sparsemat(igraph_sparsemat_t *res,
                               const igraph_matrix_t *mat,
                               igraph_real_t tol);

参数: 

res:

一个未初始化的稀疏矩阵,结果存储在此处。

mat:

密集输入矩阵。

tol:

零比较的容差。值比 tol 更接近零的值被视为零,并且不会包含在稀疏矩阵中。

返回值: 

错误代码。

另请参阅: 

igraph_sparsemat_as_matrix() 用于反向转换。

时间复杂度:O(mn),密集矩阵中元素的数量。

4.9.3. igraph_sparsemat_as_matrix — 将稀疏矩阵转换为密集矩阵。

igraph_error_t igraph_sparsemat_as_matrix(igraph_matrix_t *res,
                               const igraph_sparsemat_t *spmat);

参数: 

res:

指向初始化的矩阵的指针,结果存储在此处。它将调整为所需的大小。

spmat:

输入稀疏矩阵,采用三元组或列压缩格式。

返回值: 

错误代码。

另请参阅: 

igraph_matrix_as_sparsemat() 用于反向转换。

时间复杂度:O(mn),密集矩阵中元素的数量。

4.10. 写入文件或屏幕

4.10.1. igraph_sparsemat_print — 将稀疏矩阵打印到文件。

igraph_error_t igraph_sparsemat_print(const igraph_sparsemat_t *A,
                           FILE *outstream);

仅打印非零条目。此函数更多地用作调试实用程序,因为目前没有函数可以从文件中读回打印的矩阵。

参数: 

A:

输入矩阵,三元组或列压缩格式。

outstream:

要打印到的流。

返回值: 

错误代码。

时间复杂度:三元组矩阵为 O(nz),列压缩矩阵为 O(n+nz)。nz 是非零元素的数量,n 是矩阵中的列数。

4.11. 已弃用的函数

4.11.1. igraph_sparsemat_copy — 复制稀疏矩阵(已弃用的别名)。

igraph_error_t igraph_sparsemat_copy(
    igraph_sparsemat_t *to, const igraph_sparsemat_t *from
);

警告

自 0.10 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_sparsemat_init_copy()

4.11.2. igraph_sparsemat_diag — 创建稀疏对角矩阵(已弃用的别名)。

igraph_error_t igraph_sparsemat_diag(
    igraph_sparsemat_t *A, igraph_integer_t nzmax, const igraph_vector_t *values,
    igraph_bool_t compress
);

警告

自 0.10 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_sparsemat_init_diag()

4.11.3. igraph_sparsemat_eye — 创建稀疏单位矩阵(已弃用的别名)。

igraph_error_t igraph_sparsemat_eye(
    igraph_sparsemat_t *A, igraph_integer_t n, igraph_integer_t nzmax,
    igraph_real_t value, igraph_bool_t compress
);

警告

自 0.10 版本起已弃用。请勿在新代码中使用此函数;请改用 igraph_sparsemat_init_eye()

5. 堆栈

5.1. igraph_stack_init — 初始化堆栈。

igraph_error_t igraph_stack_init(igraph_stack_t* s, igraph_integer_t capacity);

初始化的堆栈始终为空。

参数: 

s:

指向未初始化的堆栈的指针。

capacity:

要为其分配内存的元素的数量。

返回值: 

错误代码。

时间复杂度:O(size)。

5.2. igraph_stack_destroy — 销毁堆栈对象。

void igraph_stack_destroy(igraph_stack_t* s);

释放用于堆栈的内存。可以通过 igraph_stack_init() 再次重新初始化已销毁的堆栈。

参数: 

s:

要销毁的堆栈。

时间复杂度:O(1)。

5.3. igraph_stack_reserve — 预留内存。

igraph_error_t igraph_stack_reserve(igraph_stack_t* s, igraph_integer_t capacity);

为将来使用预留内存。堆栈的实际大小不变。

参数: 

s:

堆栈对象。

大小:

要为其预留内存的元素的数量。如果它不大于当前大小,则不会发生任何事情。

返回值: 

错误代码。

时间复杂度:应该在 O(n) 左右,堆栈的新分配大小。

5.4. igraph_stack_empty — 判断堆栈对象是否为空。

igraph_bool_t igraph_stack_empty(igraph_stack_t* s);

参数: 

s:

堆栈对象。

返回值: 

布尔值,如果堆栈为空,则为 true,否则为 false

时间复杂度:O(1)。

5.5. igraph_stack_size — 返回堆栈中的元素数量。

igraph_integer_t igraph_stack_size(const igraph_stack_t* s);

参数: 

s:

堆栈对象。

返回值: 

堆栈中的元素数量。

时间复杂度:O(1)。

5.6. igraph_stack_clear — 从堆栈中删除所有元素。

void igraph_stack_clear(igraph_stack_t* s);

参数: 

s:

堆栈对象。

时间复杂度:O(1)。

5.7. igraph_stack_push — 将元素放置在堆栈顶部。

igraph_error_t igraph_stack_push(igraph_stack_t* s, igraph_real_t elem);

如果需要,堆栈的容量会增加。

参数: 

s:

堆栈对象。

elem:

要推送的元素。

返回值: 

错误代码。

时间复杂度:如果不需要重新分配,则为 O(1),否则为 O(n),但可以确保在 O(n) 时间内执行 n 次推送操作。

5.8. igraph_stack_pop — 从堆栈顶部删除并返回一个元素。

igraph_real_t igraph_stack_pop(igraph_stack_t* s);

堆栈必须包含至少一个元素,请调用 igraph_stack_empty() 以确保这一点。

参数: 

s:

堆栈对象。

返回值: 

已删除的顶部元素。

时间复杂度:O(1)。

5.9. igraph_stack_top — 查询顶部元素。

igraph_real_t igraph_stack_top(const igraph_stack_t* s);

返回堆栈的顶部元素,而不删除它。堆栈必须为非空。

参数: 

s:

堆栈。

返回值: 

顶部元素。

时间复杂度:O(1)。

6. 双端队列

这是双端队列的经典数据类型。如果需要先进先出 (FIFO) 行为,则大多数时候会使用它。请参阅以下操作。

示例 7.10.  文件 examples/simple/dqueue.c

#include <igraph.h>

int main(void) {

    igraph_dqueue_t q;

    /* igraph_dqueue_init, igraph_dqueue_destroy, igraph_dqueue_empty */
    igraph_dqueue_init(&q, 5);
    if (!igraph_dqueue_empty(&q)) {
        return 1;
    }
    igraph_dqueue_destroy(&q);

    /* igraph_dqueue_push, igraph_dqueue_pop */
    igraph_dqueue_init(&q, 4);
    igraph_dqueue_push(&q, 1);
    igraph_dqueue_push(&q, 2);
    igraph_dqueue_push(&q, 3);
    igraph_dqueue_push(&q, 4);
    if (igraph_dqueue_pop(&q) != 1) {
        return 2;
    }
    if (igraph_dqueue_pop(&q) != 2) {
        return 3;
    }
    if (igraph_dqueue_pop(&q) != 3) {
        return 4;
    }
    if (igraph_dqueue_pop(&q) != 4) {
        return 5;
    }
    igraph_dqueue_destroy(&q);

    /* igraph_dqueue_clear, igraph_dqueue_size */
    igraph_dqueue_init(&q, 0);
    if (igraph_dqueue_size(&q) != 0) {
        return 6;
    }
    igraph_dqueue_clear(&q);
    if (igraph_dqueue_size(&q) != 0) {
        return 7;
    }
    for (int i = 0; i < 10; i++) {
        igraph_dqueue_push(&q, i);
    }
    igraph_dqueue_clear(&q);
    if (igraph_dqueue_size(&q) != 0) {
        return 8;
    }
    igraph_dqueue_destroy(&q);

    /* TODO: igraph_dqueue_full */

    /* igraph_dqueue_head, igraph_dqueue_back, igraph_dqueue_pop_back */
    igraph_dqueue_init(&q, 0);
    for (int i = 0; i < 10; i++) {
        igraph_dqueue_push(&q, i);
    }
    for (int i = 0; i < 10; i++) {
        if (igraph_dqueue_head(&q) != 0) {
            return 9;
        }
        if (igraph_dqueue_back(&q) != 9 - i) {
            return 10;
        }
        if (igraph_dqueue_pop_back(&q) != 9 - i) {
            return 11;
        }
    }
    igraph_dqueue_destroy(&q);

    /* print */
    igraph_dqueue_init(&q, 4);
    igraph_dqueue_push(&q, 1);
    igraph_dqueue_push(&q, 2);
    igraph_dqueue_push(&q, 3);
    igraph_dqueue_push(&q, 4);
    igraph_dqueue_pop(&q);
    igraph_dqueue_pop(&q);
    igraph_dqueue_push(&q, 5);
    igraph_dqueue_push(&q, 6);
    igraph_dqueue_print(&q);

    igraph_dqueue_clear(&q);
    igraph_dqueue_print(&q);

    igraph_dqueue_destroy(&q);

    if (IGRAPH_FINALLY_STACK_SIZE() != 0) {
        return 12;
    }

    return 0;
}


6.1. igraph_dqueue_init — 初始化双端队列 (deque)。

igraph_error_t igraph_dqueue_init(igraph_dqueue_t* q, igraph_integer_t capacity);

队列将始终为空。

参数: 

q:

指向未初始化的 deque 的指针。

capacity:

要为其分配内存的元素数量。

返回值: 

错误代码。

时间复杂度:O(capacity)。

6.2. igraph_dqueue_destroy — 销毁双端队列。

void igraph_dqueue_destroy(igraph_dqueue_t* q);

参数: 

q:

要销毁的队列。

时间复杂度:O(1)。

6.3. igraph_dqueue_empty — 判断队列是否为空。

igraph_bool_t igraph_dqueue_empty(const igraph_dqueue_t* q);

参数: 

q:

队列。

返回值: 

布尔值,如果 q 包含至少一个元素,则为 true,否则为 false。

时间复杂度:O(1)。

6.4. igraph_dqueue_full — 检查队列是否已满。

igraph_bool_t igraph_dqueue_full(igraph_dqueue_t* q);

如果队列已满,则下一个 igraph_dqueue_push() 操作将分配更多内存。

参数: 

q:

队列。

返回值: 

如果 q 已满,则为 true,否则为 false

时间复杂度:O(1)。

6.5. igraph_dqueue_clear — 从队列中删除所有元素。

void igraph_dqueue_clear(igraph_dqueue_t* q);

参数: 

q:

队列。

时间复杂度:O(1)。

6.6. igraph_dqueue_size — 队列中的元素数量。

igraph_integer_t igraph_dqueue_size(const igraph_dqueue_t* q);

参数: 

q:

队列。

返回值: 

整数,队列中当前的元素数量。

时间复杂度:O(1)。

6.7. igraph_dqueue_head — 队列的头部。

igraph_real_t igraph_dqueue_head(const igraph_dqueue_t* q);

队列必须包含至少一个元素。

参数: 

q:

队列。

返回值: 

队列中的第一个元素。

时间复杂度:O(1)。

6.8. igraph_dqueue_back — 队列的尾部。

igraph_real_t igraph_dqueue_back(const igraph_dqueue_t* q);

队列必须包含至少一个元素。

参数: 

q:

队列。

返回值: 

队列中的最后一个元素。

时间复杂度:O(1)。

6.9. igraph_dqueue_get — 访问队列中的元素。

igraph_real_t igraph_dqueue_get(const igraph_dqueue_t *q, igraph_integer_t idx);

参数: 

q:

队列。

idx:

队列中元素的索引。

返回值: 

所需的元素。

时间复杂度:O(1)。

6.10. igraph_dqueue_pop — 删除头部。

igraph_real_t igraph_dqueue_pop(igraph_dqueue_t* q);

删除并返回队列中的第一个元素。队列必须为非空。

参数: 

q:

输入队列。

返回值: 

队列中的第一个元素。

时间复杂度:O(1)。

6.11. igraph_dqueue_pop_back — 删除尾部。

igraph_real_t igraph_dqueue_pop_back(igraph_dqueue_t* q);

删除并返回队列中的最后一个元素。队列必须为非空。

参数: 

q:

队列。

返回值: 

队列中的最后一个元素。

时间复杂度:O(1)。

6.12. igraph_dqueue_push — 追加一个元素。

igraph_error_t igraph_dqueue_push(igraph_dqueue_t* q, igraph_real_t elem);

将一个元素追加到队列的末尾。

参数: 

q:

队列。

elem:

要追加的元素。

返回值: 

错误代码。

时间复杂度:如果不需要内存分配,则为 O(1),否则为 O(n),队列中元素的数量。但请注意,通过始终分配当前队列大小的两倍的内存,我们确保始终可以在最多 O(n) 时间内完成 n 次推送操作。(假设内存分配最多是线性的。)

7. 最大堆和最小堆

7.1. igraph_heap_init — 初始化一个空堆对象。

igraph_error_t igraph_heap_init(igraph_heap_t* h, igraph_integer_t capacity);

创建一个堆,并为某些元素分配内存。

参数: 

h:

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

capacity:

要为其分配内存的元素的数量。

返回值: 

错误代码。

时间复杂度:O(alloc_size),假设内存分配是线性操作。

7.2. igraph_heap_init_array — 从数组构建一个堆。

igraph_error_t igraph_heap_init_array(igraph_heap_t *h, const igraph_real_t *data, igraph_integer_t len);

从数组初始化一个堆对象。当然,堆也已构建(构造函数)。

参数: 

h:

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

数据:

指向基本数据类型数组的指针。

len:

data 处的数组的长度。

返回值: 

错误代码。

时间复杂度:O(n),堆中的元素数量。

7.3. igraph_heap_destroy — 销毁一个初始化的堆对象。

void igraph_heap_destroy(igraph_heap_t* h);

参数: 

h:

堆对象。

时间复杂度:O(1)。

7.4. igraph_heap_clear — 从堆中删除所有元素。

void igraph_heap_clear(igraph_heap_t* h);

此函数仅将堆的大小设置为零,它不会释放任何已分配的内存。为此,您必须调用 igraph_heap_destroy()

参数: 

h:

堆对象。

时间复杂度:O(1)。

7.5. igraph_heap_empty — 判断堆对象是否为空。

igraph_bool_t igraph_heap_empty(const igraph_heap_t* h);

参数: 

h:

堆对象。

返回值: 

如果堆为空,则为 true,否则为 false

时间复杂度:O(1)。

7.6. igraph_heap_push — 添加一个元素。

igraph_error_t igraph_heap_push(igraph_heap_t* h, igraph_real_t elem);

将一个元素添加到堆中。

参数: 

h:

堆对象。

elem:

要添加的元素。

返回值: 

错误代码。

时间复杂度:如果不需要重新分配,则 n 是堆中元素的数量,为 O(log n),否则为 O(n)。可以确保在 O(n log n) 时间内执行 n 次推送操作。

7.7. igraph_heap_top — 顶部元素。

igraph_real_t igraph_heap_top(const igraph_heap_t* h);

对于最大堆,这是堆中最大的元素,对于最小堆,这是堆中最小的元素。

参数: 

h:

堆对象。

返回值: 

顶部元素。

时间复杂度:O(1)。

7.8. igraph_heap_delete_top — 删除并返回顶部元素。

igraph_real_t igraph_heap_delete_top(igraph_heap_t* h);

删除并返回堆的顶部元素。对于最大堆,这是最大的元素,对于最小堆,这是最小的元素。

参数: 

h:

堆对象。

返回值: 

顶部元素。

时间复杂度:O(log n),n 是堆中元素的数量。

7.9. igraph_heap_size — 堆中的元素数量。

igraph_integer_t igraph_heap_size(const igraph_heap_t* h);

给出堆中的元素数量。

参数: 

h:

堆对象。

返回值: 

堆中的元素数量。

时间复杂度:O(1)。

7.10. igraph_heap_reserve — 为堆预留内存。

igraph_error_t igraph_heap_reserve(igraph_heap_t* h, igraph_integer_t capacity);

为将来使用分配内存。堆的大小不变。如果堆大于 capacity 参数,则不会发生任何事情。

参数: 

h:

堆对象。

capacity:

要为其分配内存的元素的数量。

返回值: 

错误代码。

时间复杂度:如果 capacity 大于当前元素数量,则为 O(capacity)。否则为 O(1)。

8. 字符串向量

8.1. igraph_strvector_init — 初始化字符串向量。
8.2. igraph_strvector_init_copy — 通过复制初始化。
8.3. igraph_strvector_destroy — 释放为字符串向量分配的内存。
8.4. STR — 索引字符串向量。
8.5. igraph_strvector_get — 检索字符串向量的元素。
8.6. igraph_strvector_set — 从字符串设置字符串向量的元素。
8.7. igraph_strvector_set_len — 给定缓冲区及其大小,设置字符串向量的元素。
8.8. igraph_strvector_push_back — 将元素添加到字符串向量的末尾。
8.9. igraph_strvector_push_back_len — 将给定长度的字符串添加到字符串向量的末尾。
8.10. igraph_strvector_swap_elements — 交换字符串向量中的两个元素。
8.11. igraph_strvector_remove — 从字符串向量中删除单个元素。
8.12. igraph_strvector_remove_section — 从字符串向量中删除一个部分。
8.13. igraph_strvector_append — 连接两个字符串向量。
8.14. igraph_strvector_merge — 将一个字符串向量的内容移动到另一个字符串向量的末尾。
8.15. igraph_strvector_clear — 从字符串向量中删除所有元素。
8.16. igraph_strvector_resize — 调整字符串向量的大小。
8.17. igraph_strvector_reserve — 为字符串向量保留内存。
8.18. igraph_strvector_resize_min — 释放字符串向量中未使用的内存。
8.19. igraph_strvector_size — 返回字符串向量的大小。
8.20. igraph_strvector_capacity — 返回字符串向量的容量。
8.21. 弃用的函数

igraph_strvector_t 类型是空终止字符串的向量。它在内部用于存储图属性名称以及 C 属性处理程序中的字符串属性。

此容器自动管理其元素的内存。igraph_strvector_t 中的字符串应被视为常量,并且不应直接修改。添加新元素的函数总是复制传递给它们的字符串。

示例 7.11. 文件 examples/simple/igraph_strvector.c

#include <igraph.h>

void strvector_print(const igraph_strvector_t sv) {
    igraph_integer_t i, s = igraph_strvector_size(&sv);
    for (i = 0; i < s; i++) {
        printf("---%s---\n", igraph_strvector_get(&sv, i));
    }
    printf("\n");
}

int main(void) {

    igraph_strvector_t sv1, sv2;

    printf("Initializing and setting elements:\n");
    igraph_strvector_init(&sv1, 5);

    igraph_strvector_set(&sv1, 0, "zero");
    igraph_strvector_set(&sv1, 1, "one");
    igraph_strvector_set(&sv1, 2, "two");
    igraph_strvector_set(&sv1, 3, "three");
    igraph_strvector_set(&sv1, 4, "four");
    strvector_print(sv1);

    printf("strvector size after first removing one element, and then the rest:\n");
    igraph_strvector_remove(&sv1, 4);
    igraph_strvector_remove_section(&sv1, 0, 4);
    printf("%" IGRAPH_PRId "\n\n", igraph_strvector_size(&sv1));

    printf("Resize to three elements, and set them:\n");
    igraph_strvector_resize(&sv1, 3);
    igraph_strvector_set(&sv1, 0, "zero");
    igraph_strvector_set(&sv1, 1, "one");
    igraph_strvector_set(&sv1, 2, "two");
    strvector_print(sv1);

    printf("Then copy the first element over the third element:\n");
    igraph_strvector_set(&sv1, 2, igraph_strvector_get(&sv1, 0));
    strvector_print(sv1);

    printf("Make a copy of the strvector and set the last element of the copy:\n");
    igraph_strvector_init_copy(&sv2, &sv1);
    igraph_strvector_set(&sv2, 2, "copy two");
    strvector_print(sv2);

    printf("Append the copy to the strvector:\n");
    igraph_strvector_append(&sv1, &sv2);
    strvector_print(sv1);

    printf("Add two strings at the end:\n");
    igraph_strvector_push_back(&sv1, "zeroth");
    igraph_strvector_push_back(&sv1, "first");
    strvector_print(sv1);
    igraph_strvector_destroy(&sv1);

    printf("strvector size after clearing it:\n");
    igraph_strvector_clear(&sv2);
    printf("%" IGRAPH_PRId "\n", igraph_strvector_size(&sv2));

    igraph_strvector_destroy(&sv2);

    return 0;
}


8.1. igraph_strvector_init — 初始化字符串向量。

igraph_error_t igraph_strvector_init(igraph_strvector_t *sv, igraph_integer_t size);

为字符串向量保留内存,必须先初始化字符串向量,然后才能在其上调用其他函数。字符串向量的所有元素都设置为空字符串。

参数: 

sv:

指向已初始化字符串向量的指针。

len:

字符串向量的(初始)长度。

返回值: 

错误代码。

时间复杂度:O(len)。

8.2. igraph_strvector_init_copy — 通过复制初始化。

igraph_error_t igraph_strvector_init_copy(igraph_strvector_t *to,
                                          const igraph_strvector_t *from);

通过复制另一个字符串向量来初始化字符串向量。

参数: 

:

指向未初始化字符串向量的指针。

:

要复制的另一个字符串向量。

返回值: 

错误代码。

时间复杂度:O(l),from 中字符串的总长度。

8.3. igraph_strvector_destroy — 释放为字符串向量分配的内存。

void igraph_strvector_destroy(igraph_strvector_t *sv);

销毁字符串向量。稍后可以使用 igraph_strvector_init() 重新初始化它。

参数: 

sv:

字符串向量。

时间复杂度:O(l),字符串的总长度,可能取决于内存管理器。

8.4. STR — 索引字符串向量。

#define STR(sv,i)

这是一个宏,允许查询字符串向量的元素,就像 igraph_strvector_get() 一样。请注意,此宏不能用于设置元素。请使用 igraph_strvector_set() 来设置元素。

参数: 

sv:

字符串向量

i:

元素的索引。

返回值: 

位置 i 处的元素。

时间复杂度:O(1)。

警告

自 0.10.9 版本起已弃用。请不要在新代码中使用此函数;请改用 igraph_strvector_get()

8.5. igraph_strvector_get — 检索字符串向量的元素。

const char *igraph_strvector_get(const igraph_strvector_t *sv, igraph_integer_t idx);

查询字符串向量的元素。返回的字符串不得修改。

参数: 

sv:

输入字符串向量。

idx:

要查询的元素的索引。

时间复杂度:O(1)。

8.6. igraph_strvector_set — 从字符串设置字符串向量的元素。

igraph_error_t igraph_strvector_set(igraph_strvector_t *sv, igraph_integer_t idx,
                         const char *value);

提供的 value 被复制到字符串向量中的 idx 位置。

参数: 

sv:

字符串向量。

idx:

要设置的位置。

:

新值。

返回值: 

错误代码。

时间复杂度:O(l),新字符串的长度。如果需要重新分配,则可能会更多,具体取决于内存管理。

8.7. igraph_strvector_set_len — 给定缓冲区及其大小,设置字符串向量的元素。

igraph_error_t igraph_strvector_set_len(igraph_strvector_t *sv, igraph_integer_t idx,
                          const char *value, size_t len);

这几乎与 igraph_strvector_set 相同,但新值不是以零结尾的字符串,而是给出了它的长度。

参数: 

sv:

字符串向量。

idx:

要设置的位置。

:

新值。

len:

新值的长度。

返回值: 

错误代码。

时间复杂度:O(l),新字符串的长度。如果需要重新分配,则可能会更多,具体取决于内存管理。

8.8. igraph_strvector_push_back — 将元素添加到字符串向量的末尾。

igraph_error_t igraph_strvector_push_back(igraph_strvector_t *sv, const char *value);

参数: 

sv:

字符串向量。

:

要添加的字符串;它将被复制。

返回值: 

错误代码。

时间复杂度:O(n+l),n 是字符串的总数,l 是新字符串的长度。

8.9. igraph_strvector_push_back_len — 将给定长度的字符串添加到字符串向量的末尾。

igraph_error_t igraph_strvector_push_back_len(
        igraph_strvector_t *sv,
        const char *value, igraph_integer_t len);

参数: 

sv:

字符串向量。

:

要添加的字符串的开头。最多复制 len 个字符。

len:

字符串的长度。

返回值: 

错误代码。

时间复杂度:O(n+l),n 是字符串的总数,l 是新字符串的长度。

8.10. igraph_strvector_swap_elements — 交换字符串向量中的两个元素。

void igraph_strvector_swap_elements(igraph_strvector_t *sv, igraph_integer_t i, igraph_integer_t j);

请注意,目前不执行范围检查。

参数: 

sv:

字符串向量。

i:

第一个元素的索引。

j:

第二个元素的索引(可能与第一个元素相同)。

时间复杂度:O(1)。

8.11. igraph_strvector_remove — 从字符串向量中删除单个元素。

void igraph_strvector_remove(igraph_strvector_t *sv, igraph_integer_t elem);

字符串将短一个。

参数: 

sv:

字符串向量。

elem:

要删除的元素的索引。

时间复杂度:O(n),字符串的长度。

8.12. igraph_strvector_remove_section — 从字符串向量中删除一个部分。

void igraph_strvector_remove_section(
        igraph_strvector_t *sv, igraph_integer_t from, igraph_integer_t to);

此函数从字符串向量中删除范围 [from, to)

参数: 

sv:

字符串向量。

:

要删除的第一个元素的位置。

:

第一个要删除的元素的位置。

8.13. igraph_strvector_append — 连接两个字符串向量。

igraph_error_t igraph_strvector_append(igraph_strvector_t *to,
                            const igraph_strvector_t *from);

from 向量的内容附加到 to 向量。如果在此操作后不再需要 from 向量,请使用 igraph_strvector_merge() 以获得更好的性能。

参数: 

:

第一个字符串向量,结果存储在此处。

:

第二个字符串向量,它保持不变。

返回值: 

错误代码。

另请参阅: 

时间复杂度:O(n+l2),n 是新字符串向量中字符串的数量,l2 是 from 字符串向量中字符串的总长度。

8.14. igraph_strvector_merge — 将一个字符串向量的内容移动到另一个字符串向量的末尾。

igraph_error_t igraph_strvector_merge(igraph_strvector_t *to, igraph_strvector_t *from);

from 向量的内容传输到 to 的末尾,同时清除 from。如果此操作失败,则两个向量都保持不变。此函数不复制或重新分配单个字符串,因此它比 igraph_strvector_append() 性能更好。

参数: 

:

目标向量。from 的内容将附加到它。

:

源向量。它将被清除。

返回值: 

错误代码。

另请参阅: 

时间复杂度:如果 to 有足够的容量,则为 O(l2),否则为 O(2*l1+l2),其中 l1 和 l2 分别是 to 和 \from 的长度。

8.15. igraph_strvector_clear — 从字符串向量中删除所有元素。

void igraph_strvector_clear(igraph_strvector_t *sv);

在此操作之后,字符串向量将为空。

参数: 

sv:

字符串向量。

时间复杂度:O(l),字符串的总长度,可能更少,具体取决于内存管理器。

8.16. igraph_strvector_resize — 调整字符串向量的大小。

igraph_error_t igraph_strvector_resize(igraph_strvector_t *sv, igraph_integer_t newsize);

如果新大小大于当前大小,则添加空字符串;如果小于当前大小,则删除不需要的元素。

参数: 

sv:

字符串向量。

newsize:

新大小。

返回值: 

错误代码。

时间复杂度:O(n),如果向量变大,则为字符串的数量;O(l),如果向量变小,则为已删除字符串的总长度,可能更少,具体取决于内存管理。

8.17. igraph_strvector_reserve — 为字符串向量保留内存。

igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, igraph_integer_t capacity);

igraph 字符串向量是灵活的,它们可以增长和缩小。但是,增长偶尔需要复制向量中的数据。为了避免这种情况,您可以调用此函数来为向量的未来增长保留空间。

请注意,此函数不会更改字符串向量的大小。让我们看一个小例子来阐明这一点:如果您为 100 个字符串保留空间,并且您的向量的大小为(并且仍然是)60,那么您肯定可以在复制之前向向量添加额外的 40 个字符串。

参数: 

sv:

字符串向量对象。

capacity:

字符串向量的新的已分配大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:依赖于操作系统,应该在 O(n) 左右,n 是向量的新已分配大小。

8.18. igraph_strvector_resize_min — 释放字符串向量中未使用的内存。

void igraph_strvector_resize_min(igraph_strvector_t *sv);

此函数尝试释放字符串向量中未使用的保留存储空间。如果成功,igraph_strvector_size()igraph_strvector_capacity() 将相同。字符串向量中的数据始终被保留,即使释放不成功。

参数: 

sv:

字符串向量。

时间复杂度:取决于操作系统,最多 O(n)。

8.19. igraph_strvector_size — 返回字符串向量的大小。

igraph_integer_t igraph_strvector_size(const igraph_strvector_t *sv);

参数: 

sv:

字符串向量。

返回值: 

字符串向量的长度。

时间复杂度:O(1)。

8.20. igraph_strvector_capacity — 返回字符串向量的容量。

igraph_integer_t igraph_strvector_capacity(const igraph_strvector_t *sv);

参数: 

sv:

字符串向量。

返回值: 

字符串向量的容量。

时间复杂度:O(1)。

8.21. 弃用的函数

8.21.1. igraph_strvector_copy — 通过复制初始化(已弃用的别名)。

igraph_error_t igraph_strvector_copy(igraph_strvector_t *to,
                          const igraph_strvector_t *from);

警告

自 0.10.0 版本起已弃用。请不要在新代码中使用此函数;请改用 igraph_strvector_init_copy()

8.21.2. igraph_strvector_add — 将元素添加到字符串向量的末尾(已弃用的别名)。

igraph_error_t igraph_strvector_add(igraph_strvector_t *sv, const char *value);

警告

自 0.10.0 版本起已弃用。请不要在新代码中使用此函数;请改用 igraph_strvector_push_back()

8.21.3. igraph_strvector_set2 — 给定缓冲区及其大小,设置字符串向量的元素(已弃用的别名)。

igraph_error_t igraph_strvector_set2(
    igraph_strvector_t *sv, igraph_integer_t idx, const char *value, size_t len
);

警告

自 0.10.0 版本起已弃用。请不要在新代码中使用此函数;请改用 igraph_strvector_set_len()

9. 向量、矩阵和图的列表

9.1.  关于 igraph_vector_list_t 对象

igraph_vector_list_t 数据类型本质上是一个 igraph_vector_t 对象的列表,具有自动内存管理。它类似于 C++ 标准库中的 vector 模板(但比它简单得多),其中元素本身就是向量。

存在 igraph_vector_list_t 的多个变体;基本变体存储双精度向量(即,每个项都是一个 igraph_vector_t),但也有整数的 igraph_vector_int_list_t(其中每个项都是一个 igraph_vector_int_t),双精度矩阵的 igraph_matrix_list_t 等。以下列表总结了当前库中可用的变体

  • igraph_vector_list_t 用于浮点数向量的列表 (igraph_vector_t)

  • igraph_vector_int_list_t 用于整数向量的列表 (igraph_vector_int_t)

  • igraph_matrix_list_t 用于浮点数矩阵的列表 (igraph_matrix_t)

  • igraph_graph_list_t 用于图的列表 (igraph_t)

在许多情况下,igraph 中使用向量列表,例如,返回路径、集团或顶点集合的列表时。期望或返回数字向量列表的函数通常使用 igraph_vector_list_tigraph_vector_int_list_t 来实现此目的。当列表中的向量应该保存顶点或边标识符时,使用整数向量列表;而当向量应该保存小数值或无穷大时,使用浮点向量列表。

igraph_vector_list_t 对象及其变体中的元素从零开始索引,我们遵循通常的 C 约定。

以下针对 igraph_vector_list_t 描述的几乎所有函数也存在于所有其他向量列表变体中。这些变体没有单独记录;如果您需要另一个变体的函数,您可以简单地将 vector_list 替换为 vector_int_list。例如,要初始化整数向量列表,您需要使用 igraph_vector_int_list_init(),而不是 igraph_vector_list_init()

在深入了解与向量列表相关的函数的详细描述之前,我们还必须讨论这些对象的所有权规则。最重要的规则是列表中的向量归列表本身所有,这意味着用户负责为向量分配内存或释放与向量关联的内存。列表负责在列表中创建新项时分配和初始化向量,并且列表还负责在从列表中删除项而不将所有权传递给用户时销毁这些项。因此,列表可能不包含“未初始化”或“空”项;每个项在存在时都会被初始化。如果您创建一个包含一百万个向量的列表,您不仅为一百万个 igraph_vector_t 对象分配内存,而且还初始化了一百万个向量。此外,如果您有一个包含一百万个向量的列表,并且您通过调用 igraph_vector_list_clear() 清除该列表,则该列表将隐式销毁这些列表,并且您可能持有的任何指向项的指针都会立即失效。

说到指针,使用列表中向量的典型方法是通过 igraph_vector_list_get_ptr() 方法获取指向其中一个项的指针,然后将此指针传递给可以操作 igraph_vector_t 对象的函数。但是,请注意,指针是临时的,因为当列表被修改时,它们可能会失效,因为如果需要更多空间,修改可能涉及重新分配列表的内部存储,并且您获得的指针不会跟随重新分配。这种限制在 igraph_vector_list_t 的实际使用中并不经常出现,总的来说,自动内存管理的优势超过了这种限制。

9.2.  构造函数和析构函数

igraph_vector_list_t 对象在使用前必须初始化,这类似于在它们上面调用构造函数。igraph_vector_list_init() 是基本构造函数;它创建给定长度的列表,并将新创建列表中的每个向量初始化为零长度。

如果不再需要 igraph_vector_list_t 对象,则应通过调用 igraph_vector_list_t 析构函数 igraph_vector_list_destroy() 来销毁它以释放其已分配的内存。由于所有权规则,调用析构函数还会销毁向量列表中的所有向量。如果您想保留向量列表中的一些向量,您需要使用 igraph_vector_init_copy()igraph_vector_update() 复制它们,或者您需要通过调用 igraph_vector_list_pop_back()igraph_vector_list_remove()igraph_vector_list_remove_fast() 将它们从列表中删除并取得所有权。

9.2.1. igraph_vector_list_init — 初始化向量列表(构造函数)。

igraph_error_t igraph_vector_list_init(igraph_vector_list_t *v, igraph_integer_t size);

此函数构造给定大小的向量列表,并将新创建列表中的每个向量初始化为空向量。

由此函数初始化的向量对象由列表拥有,并且当列表被 igraph_vector_list_destroy() 销毁时,它们将被自动销毁。

参数: 

v:

指向尚未初始化的向量列表的指针。

大小:

列表的大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,分配 O(n) 个元素并初始化相应向量所需的时间量;n 是元素的数量。

9.2.2. igraph_vector_list_destroy — 销毁向量列表对象。

void igraph_vector_list_destroy(igraph_vector_list_t *v);

通过 igraph_vector_list_init() 初始化的所有列表都应由此函数正确销毁。如果您想再次使用销毁的向量列表,则需要通过 igraph_vector_list_init() 重新初始化它。

当列表被销毁时,列表中的向量也会被隐式销毁。

参数: 

v:

指向要销毁的(先前已初始化的)列表对象的指针。

时间复杂度:操作系统相关。

9.3.  访问元素

可以使用 igraph_vector_list_get_ptr() 函数访问向量列表的元素。该函数返回指向列表中给定索引处的向量的指针,然后您可以将此指针传递给其他可以查询或操作向量的函数。只要列表本身没有被修改,指针本身就可以保证保持有效;但是,对列表的任何修改都会使指针失效,即使是与指针指向的向量看似无关的修改(例如,在列表末尾添加新向量)。这是因为如果新元素不适合已分配的空间,则列表数据结构可能被迫重新分配其内部存储,并且不能保证重新分配的块保留在同一内存位置(通常它会被移动到其他地方)。

请注意,适用于普通向量的标准 VECTOR 宏不适用于向量列表来访问第 i 个元素(但当然您可以使用它来索引您从向量列表中使用 igraph_vector_list_get_ptr() 检索到的现有向量)。这是因为宏表示法将允许一个人用另一个向量覆盖列表中的向量,而列表对此一无所知,因此列表将无法销毁被新向量覆盖的向量。

igraph_vector_list_tail_ptr() 返回指向列表中最后一个向量的指针,如果列表为空,则返回 NULL。没有 igraph_vector_list_head_ptr(),但是,很容易编写 igraph_vector_list_get_ptr(v, 0) 代替。

9.3.1. igraph_vector_list_get_ptr — 向量列表中向量的地址。

igraph_vector_t *igraph_vector_list_get_ptr(const igraph_vector_list_t *v, igraph_integer_t pos);

参数: 

v:

列表对象。

位置:

向量在列表中的位置。第一个向量的位置为零。

返回值: 

指向向量的指针。只要底层向量列表未被修改,它就保持有效。

时间复杂度:O(1)。

9.3.2. igraph_vector_list_tail_ptr — 向量列表中最后一个向量的地址。

igraph_vector_t *igraph_vector_list_tail_ptr(const igraph_vector_list_t *v);

参数: 

v:

列表对象。

返回值: 

指向列表中最后一个向量的指针,如果列表为空,则为 NULL

时间复杂度:O(1)。

9.3.3. igraph_vector_list_set — 设置列表中给定索引处的向量。

void igraph_vector_list_set(igraph_vector_list_t *v, igraph_integer_t pos, igraph_vector_t *e);

此函数销毁列表中给定索引 pos 处已有的向量,并将其替换为 e 指向的向量。 e 指向的向量的所有权由列表获取,因此用户不再负责销毁 e;当列表本身被销毁或如果 e 从列表中删除而没有将所有权传递给其他地方时,它将被销毁。

参数: 

v:

列表对象。

位置:

要修改的列表中的索引。

e:

要在列表中设置的向量。

时间复杂度:O(1)。

9.3.4. igraph_vector_list_replace — 将列表中给定索引处的向量替换为另一个向量。

void igraph_vector_list_replace(igraph_vector_list_t *v, igraph_integer_t pos, igraph_vector_t *e);

此函数将列表中给定索引 pos 处已有的向量替换为 e 指向的向量。e 指向的向量的所有权由列表获取,因此用户不再负责销毁 e。同时,原先在列表中位置 pos 处的向量的所有权将被转移给调用方,并且 e 将被更新为指向它,因此调用方负责在不再需要向量时销毁它。

参数: 

v:

列表对象。

位置:

要修改的列表中的索引。

e:

要与列表中已有的向量交换的向量。

时间复杂度:O(1)。

9.4.  向量属性

9.4.1. igraph_vector_list_empty — 确定列表的大小是否为零。

igraph_bool_t igraph_vector_list_empty(const igraph_vector_list_t *v);

参数: 

v:

列表对象。

返回值: 

如果列表的大小为零,则为 True,否则为 false。

时间复杂度:O(1)。

9.4.2. igraph_vector_list_size — 向量列表的大小。

igraph_integer_t igraph_vector_list_size(const igraph_vector_list_t *v);

返回列表中存储的向量数量。

参数: 

v:

列表对象

返回值: 

列表的大小。

时间复杂度:O(1)。

9.4.3. igraph_vector_list_capacity — 返回列表的已分配容量。

igraph_integer_t igraph_vector_list_capacity(const igraph_vector_list_t *v);

请注意,这可能与列表的大小不同(通过 igraph_vector_list_size() 查询),并且指定列表可以容纳多少向量,而无需重新分配。

参数: 

v:

指向要查询的(先前已初始化的)列表对象的指针。

返回值: 

已分配容量。

另请参阅: 

时间复杂度:O(1)。

9.5. 调整大小操作

9.5.1. igraph_vector_list_clear — 从向量列表中删除所有元素。

void igraph_vector_list_clear(igraph_vector_list_t *v);

此函数将列表的大小设置为零,并且还会销毁在清除列表之前放置在列表中的所有向量。

参数: 

v:

列表对象。

时间复杂度:O(n),n 是要删除的项的数量。

9.5.2. igraph_vector_list_reserve — 为列表保留内存。

igraph_error_t igraph_vector_list_reserve(igraph_vector_list_t *v, igraph_integer_t capacity);

igraph 列表是灵活的,它们可以增长和缩小。但是,增长偶尔需要复制列表中的数据。为了避免这种情况,您可以调用此函数来为列表的未来增长保留空间。

请注意,此函数不会更改列表的大小,也不会初始化任何新向量。让我们看一个小例子来阐明这一点:如果您为 100 个元素保留空间,并且您的列表的大小为(并且仍然是)60,那么您肯定可以在复制之前向列表中添加额外的 40 个新向量。

参数: 

v:

列表对象。

capacity:

列表的新的已分配大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,应该大约为 O(n),n 是列表的新已分配大小。

9.5.3. igraph_vector_list_resize — 调整向量列表的大小。

igraph_error_t igraph_vector_list_resize(igraph_vector_list_t *v, igraph_integer_t new_size);

请注意,此函数不会释放任何内存,只是将列表的大小设置为给定的大小。另一方面,如果新大小大于以前的大小,它可以分配更多内存。

当新大小大于当前大小时,列表中新添加的向量将被初始化为空向量。当新大小小于当前大小时,从列表末尾删除的向量将被自动销毁。

参数: 

v:

列表对象

new_size:

列表的新大小。

返回值: 

错误代码,如果没有足够的内存,则为 IGRAPH_ENOMEM。请注意,如果列表变小,此函数永远不会返回错误。

另请参阅: 

igraph_vector_list_reserve() 用于为列表的未来扩展分配内存。

时间复杂度:如果新尺寸较小,则为 O(m)(m 是从列表中删除的项数);如果新尺寸较大,则取决于操作系统。 在后一种情况下,通常约为 O(n),其中 n 是向量的新尺寸。

9.5.4. igraph_vector_list_push_back — 将现有向量追加到列表中,转移所有权。

igraph_error_t igraph_vector_list_push_back(igraph_vector_list_t *v, igraph_vector_t *e);

此函数将列表大小调整为一个元素更长,并将列表中最后一个元素设置为指定的向量 e。 列表获得向量的所有权,因此用户不再负责释放 e;向量将在列表本身被销毁时或如果 e 从列表中移除而没有将所有权传递给其他地方时被销毁。

参数: 

v:

列表对象。

e:

要追加到列表的向量的指针。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:取决于操作系统。 重要的是,对该函数的 n 个后续调用的时间复杂度为 O(n),即使 igraph_vector_list_reserve() 没有为新元素预留任何空间。 这是通过类似于 C++ vector 类的技巧实现的:每次为向量分配更多内存时,额外分配的内存大小与向量的当前长度相同。(我们在此假设内存分配的时间复杂度最多是线性的)。

9.5.5. igraph_vector_list_push_back_copy — 将向量的副本追加到列表中。

igraph_error_t igraph_vector_list_push_back_copy(igraph_vector_list_t *v, const igraph_vector_t *e);

此函数将列表大小调整为一个元素更长,并将作为参数指定的向量复制到最后一个元素。 新添加的元素归列表所有,但原始向量的所有权由调用者保留。

参数: 

v:

列表对象。

e:

要复制到列表末尾的向量的指针。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:与 igraph_vector_list_push_back() 相同,加上复制向量所需的时间(对于向量中的 n 个元素,时间复杂度为 O(n))。

9.5.6. igraph_vector_list_push_back_new — 将新向量追加到列表中。

igraph_error_t igraph_vector_list_push_back_new(igraph_vector_list_t *v, igraph_vector_t** e);

此函数将列表大小调整为一个元素更长。 新添加的元素将是一个空向量,归列表所有。 如果最后一个参数不是 NULL,则会在最后一个参数中返回指向新添加元素的指针。

参数: 

v:

列表对象。

结果:

指向向量指针的指针;这将更新为指向新添加的向量。 如果您不需要指向新添加的向量的指针,则可能为 NULL

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:与 igraph_vector_list_push_back() 相同。

9.5.7. igraph_vector_list_pop_back — 从向量列表中删除最后一个项目并将所有权转移给调用者。

igraph_vector_t igraph_vector_list_pop_back(igraph_vector_list_t *v);

此函数从列表中删除最后一个向量。 从列表中删除的向量将被返回,其所有权将被传递回调用者;换句话说,调用者有责任在不再需要该向量时销毁该向量。

使用空向量调用此函数是一个错误。

参数: 

v:

列表对象。

结果:

指向 igraph_vector_t 对象的指针;它将更新为从列表中删除的项目。 此向量的所有权将传递给调用者。

时间复杂度:O(1)。

9.5.8. igraph_vector_list_insert — 将现有向量插入列表中,转移所有权。

igraph_error_t igraph_vector_list_insert(igraph_vector_list_t *v, igraph_integer_t pos, igraph_vector_t *e);

此函数将 e 插入到列表中给定的索引处,并根据需要将其他项目移向列表的末尾。 列表获得向量的所有权,因此用户不再负责释放 e;向量将在列表本身被销毁时或如果 e 从列表中移除而没有将所有权传递给其他地方时被销毁。

参数: 

v:

列表对象。

位置:

要在其中插入新元素的位置。

e:

要插入列表中的向量的指针。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:O(n)。

9.5.9. igraph_vector_list_insert_copy — 将向量的副本插入到列表中。

igraph_error_t igraph_vector_list_insert_copy(igraph_vector_list_t *v, igraph_integer_t pos, const igraph_vector_t *e);

此函数将 e 的副本插入到列表中给定的索引处,并根据需要将其他项目移向列表的末尾。 新添加的元素归列表所有,但原始向量的所有权由调用者保留。

参数: 

v:

列表对象。

位置:

要在其中插入新元素的位置。

e:

要复制到列表末尾的向量的指针。

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:与 igraph_vector_list_insert() 相同,加上复制向量所需的时间(对于向量中的 n 个元素,时间复杂度为 O(n))。

9.5.10. igraph_vector_list_insert_new — 将新向量插入到列表中。

igraph_error_t igraph_vector_list_insert_new(igraph_vector_list_t *v, igraph_integer_t pos, igraph_vector_t** e);

此函数将新创建的空向量插入到列表中给定的索引处,并根据需要将其他项目移向列表的末尾。 新添加的向量归列表所有。 如果最后一个参数不是 NULL,则会在最后一个参数中返回指向新元素的指针。

参数: 

v:

列表对象。

位置:

要在其中插入新元素的位置。

结果:

指向向量指针的指针;这将更新为指向新添加的向量。 如果您不需要指向新添加的向量的指针,则可能为 NULL

返回值: 

错误代码:IGRAPH_ENOMEM:内存不足。

时间复杂度:与 igraph_vector_list_push_back() 相同。

9.5.11. igraph_vector_list_remove — 从向量列表中删除给定索引处的项目并将所有权转移给调用者。

igraph_error_t igraph_vector_list_remove(igraph_vector_list_t *v, igraph_integer_t index, igraph_vector_t *result);

此函数从列表中删除给定索引处的向量,并将列表中所有后续项目向左移动一个槽以填充空白。 从列表中删除的向量将在 e 中返回,其所有权将传递回调用者;换句话说,调用者有责任在不再需要该向量时销毁该向量。

参数: 

v:

列表对象。

index:

要删除的项目的索引。

结果:

指向 igraph_vector_t 对象的指针;它将更新为从列表中删除的项目。 此向量的所有权将传递给调用者。 在此处提供空指针是错误的。

另请参阅: 

如果您对删除的项目不感兴趣,请使用 igraph_vector_list_discard();如果您不关心列表中项目的顺序,请使用 igraph_vector_list_remove_fast()

时间复杂度:O(n),其中 n 是列表中的项目数。

9.5.12. igraph_vector_list_remove_fast — 删除向量列表中给定索引处的项目,将最后一个项目移动到其位置并将所有权转移给调用者。

igraph_error_t igraph_vector_list_remove_fast(igraph_vector_list_t *v, igraph_integer_t index, igraph_vector_t *result);

此函数从列表中删除给定索引处的向量,将列表中的最后一个项目移动到 index 以填充空白,然后将删除的向量的所有权传递回调用者;换句话说,调用者有责任在不再需要该向量时销毁该向量。

参数: 

v:

列表对象。

index:

要删除的项目的索引。

结果:

指向 igraph_vector_t 对象的指针;它将更新为从列表中删除的项目。 此向量的所有权将传递给调用者。 在此处提供空指针是错误的。

另请参阅: 

如果您想保留列表中项目的顺序,请使用 igraph_vector_list_remove();如果您对删除的项目不感兴趣,请使用 igraph_vector_list_discard_fast()

时间复杂度:O(1)。

9.5.13. igraph_vector_list_discard — 丢弃向量列表中给定索引处的项目。

void igraph_vector_list_discard(igraph_vector_list_t *v, igraph_integer_t index);

此函数从列表中删除给定索引处的向量,并将列表中所有后续项目向左移动一个槽以填充空白。 从列表中删除的向量将自动销毁。

参数: 

v:

列表对象。

index:

要丢弃和销毁的项目的索引。

另请参阅: 

如果您不关心列表中项目的顺序,请使用 igraph_vector_list_discard_fast();如果您想获得已删除项目的所有权而不是销毁它,请使用 igraph_vector_list_remove()

时间复杂度:O(n),其中 n 是列表中的项目数。

9.5.14. igraph_vector_list_discard_back — 丢弃向量列表中的最后一个项目。

void igraph_vector_list_discard_back(igraph_vector_list_t *v);

此函数从列表中删除最后一个向量并销毁它。

参数: 

v:

列表对象。

时间复杂度:O(1)。

9.5.15. igraph_vector_list_discard_fast — 丢弃向量列表中给定索引处的项目,并将最后一个项目移动到其位置。

void igraph_vector_list_discard_fast(igraph_vector_list_t *v, igraph_integer_t index);

此函数从列表中删除给定索引处的向量,并将列表中的最后一个项目移动到 index 以填充空白。 从列表中删除的向量将自动销毁。

参数: 

v:

列表对象。

index:

要丢弃和销毁的项目的索引。

另请参阅: 

如果您想保留列表中项目的顺序,请使用 igraph_vector_list_discard();如果您想获得已删除项目的所有权而不是销毁它,请使用 igraph_vector_list_remove_fast()

时间复杂度:O(1)。

9.6. 排序和重新排序

9.6.1. igraph_vector_list_permute — 根据索引向量就地置换列表的元素。

igraph_error_t igraph_vector_list_permute(igraph_vector_list_t *v, const igraph_vector_int_t* index);

此函数接受列表 v 和相应的索引向量 index,并置换 v 的元素,以便在函数执行后,v[index[i]] 移动到 v[i]。

使用不表示有效置换的索引向量调用此函数是错误的。 索引向量中的每个元素都必须介于 0 和列表长度减 1 之间(包括 0 和列表长度减 1),并且每个这样的元素必须只出现一次。 该函数不会尝试验证索引向量。 如果索引向量不满足这些条件,则可能会发生内存泄漏。

此函数采用的索引向量与从 igraph_vector_list_sort_ind() 返回的索引向量兼容;传入来自 igraph_vector_list_sort_ind() 的索引向量将对原始向量进行排序。

参数: 

v:

要置换的列表

index:

索引向量

时间复杂度:O(n),列表中的项目数。

9.6.2. igraph_vector_list_sort — 将列表的元素排序为升序。

void igraph_vector_list_sort(igraph_vector_list_t *v, int (*cmp)(const igraph_vector_t*, const igraph_vector_t*));

参数: 

v:

指向已初始化列表对象的指针。

cmp:

一个比较函数,它接受指向两个向量的指针,如果两个向量被认为是相等的,则返回零;如果第一个向量较小,则返回任何负数;如果第二个向量较小,则返回任何正数。

返回值: 

错误代码。

时间复杂度:对于 n 个元素为 O(n log n)。

9.6.3. igraph_vector_list_sort_ind — 返回一个索引置换,用于对列表进行排序。

igraph_error_t igraph_vector_list_sort_ind(
    igraph_vector_list_t *v, igraph_vector_int_t *inds,
    int (*cmp)(const igraph_vector_t*, const igraph_vector_t*)
);

将一个未排序的列表 v 作为输入,并计算一个索引数组 inds,使得 v[ inds[i] ](i 从 0 递增)是根据比较函数 cmp 排序的数组。 相同元素的索引顺序未定义。

参数: 

v:

要排序的列表

inds:

索引的输出数组。必须初始化,但将调整大小

cmp:

一个比较函数,它接受指向两个向量的指针,如果两个向量被认为是相等的,则返回零;如果第一个向量较小,则返回任何负数;如果第二个向量较小,则返回任何正数。

返回值: 

错误代码。

时间复杂度:对于 n 个元素为 O(n log n)。

9.6.4. igraph_vector_list_swap — 交换两个向量列表的所有元素。

igraph_error_t igraph_vector_list_swap(igraph_vector_list_t *v1, igraph_vector_list_t *v2);

参数: 

v1:

第一个列表。

v2:

第二个列表。

返回值: 

错误代码。

时间复杂度:O(1)。

9.6.5. igraph_vector_list_swap_elements — 交换向量列表中的两个元素。

igraph_error_t igraph_vector_list_swap_elements(igraph_vector_list_t *v1, igraph_integer_t i, igraph_integer_t j);

请注意,目前不执行范围检查。

参数: 

v:

输入列表。

i:

第一个元素的索引。

j:

第二个元素的索引(可能与第一个元素相同)。

返回值: 

错误代码,目前始终为 IGRAPH_SUCCESS

时间复杂度:O(1)。

10. 邻接表

有时,使用邻接表格式的图更容易:向量列表;每个向量都包含给定顶点的相邻顶点或关联边。 通常,如果我们需要多次迭代所有顶点的邻居,则此表示形式很好。 例如,当查找所有顶点对之间的最短路径或计算所有顶点的紧密度中心性时。

igraph_adjlist_t 存储图的邻接表。 创建后,它独立于原始图,可以使用通常的向量操作自由修改,该图不受影响。 例如,邻接表可用于有效地重新连接图的边。 如果对每个删除和插入操作都使用直接的 igraph_delete_edges()igraph_add_edges() 组合,这对于每次删除和插入操作都需要 O(|V|+|E|) 时间,因此如果重新连接许多边,则速度非常慢。 将图提取到邻接表中,对邻接表的向量执行所有重新连接操作,然后创建一个新图需要(取决于重新连接的具体方式)整个重新连接过程通常需要 O(|V|+|E|) 时间。

惰性邻接表略有不同。 创建惰性邻接表时,不会查询顶点的邻居,只会为向量分配一些内存。 首次对顶点 v 调用 igraph_lazy_adjlist_get() 时,会查询 v 的邻居并将其存储在邻接表的向量中,因此无需再次查询它们。 如果您有一个至少是线性操作(因为初始化通常是关于顶点数量的线性操作),但您不知道在计算期间会访问多少个顶点,则惰性邻接表很方便。

示例 7.12.  文件 examples/simple/adjlist.c

#include <igraph.h>

int main(void) {

    igraph_t g, g2;
    igraph_adjlist_t adjlist;
    igraph_bool_t iso;

    /* Create a directed out-tree, convert it into an adjacency list
     * representation, then reconstruct the graph from the tree and check
     * whether the two are isomorphic (they should be) */

    igraph_kary_tree(&g, 42, 3, IGRAPH_TREE_OUT);
    igraph_adjlist_init(&g, &adjlist, IGRAPH_OUT, IGRAPH_LOOPS_ONCE, IGRAPH_MULTIPLE);
    igraph_adjlist(&g2, &adjlist, IGRAPH_OUT, /* duplicate = */ 0);
    igraph_isomorphic(&g, &g2, &iso);
    if (!iso) {
        return 1;
    }
    igraph_adjlist_destroy(&adjlist);
    igraph_destroy(&g2);
    igraph_destroy(&g);

    return 0;
}


10.1. 相邻顶点

10.1.1. igraph_adjlist_init — 从给定图构造顶点邻接表。

igraph_error_t igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al,
                        igraph_neimode_t mode, igraph_loops_t loops,
                        igraph_multiple_t multiple);

创建一个向量列表,其中包含图中所有顶点的邻居。 邻接表在创建后独立于该图,例如,可以销毁和修改该图,邻接表包含其初始化时的图的状态。

此函数以排序顺序返回每个邻居列表,就像 igraph_neighbors() 一样。

从 igraph 0.10 开始,将 loops 设置为与 IGRAPH_LOOPS_TWICE 不同的值,或者将 multiple 设置为与 IGRAPH_MULTIPLE 不同的值,会产生少量性能成本。

参数: 

:

输入图。

al:

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

模式:

一个常量,用于指定邻接表中是否只包含传出 (IGRAPH_OUT)、只包含传入 (IGRAPH_IN) 或两种类型 (IGRAPH_ALL) 的邻居。 它对于无向图将被忽略。

循环:

指定如何处理循环边。 IGRAPH_NO_LOOPS 从邻接表中删除循环边。 IGRAPH_LOOPS_ONCE 使每个循环边仅在相应顶点的邻接表中出现一次。 IGRAPH_LOOPS_TWICE 使循环边在相应顶点的邻接表中出现两次,但仅当图是无向图或 mode 设置为 IGRAPH_ALL 时。

multiple:

指定如何处理多(并行)边。 IGRAPH_NO_MULTIPLE 将并行边折叠为单个边;IGRAPH_MULTIPLE 保留并行边的多重性,因此相同的顶点在另一个顶点的邻接表中出现的次数与两个顶点之间边的并行边的数量一样多。

返回值: 

错误代码。

另请参阅: 

用于获取各个顶点的邻居列表的 igraph_neighbors()

时间复杂度:O(|V|+|E|),顶点数和边数的线性关系。

10.1.2. igraph_adjlist_init_empty — 初始化一个空邻接表。

igraph_error_t igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes);

创建一个向量列表,每个顶点对应一个向量。 当您构造使用邻接表表示的图时,这很有用,因为它不需要您的图已经存在。

参数: 

no_of_nodes:

顶点的数量

al:

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

返回值: 

错误代码。

时间复杂度:O(|V|),顶点数量呈线性。

10.1.3. igraph_adjlist_init_complementer — 补图的邻接表。

igraph_error_t igraph_adjlist_init_complementer(const igraph_t *graph,
                                     igraph_adjlist_t *al,
                                     igraph_neimode_t mode,
                                     igraph_bool_t loops);

此函数为输入图的补图创建邻接表。 在补图中,所有原始图中不存在的边都存在。 输入图中的多条边将被忽略。

此函数以排序顺序返回每个邻居列表。

参数: 

:

输入图。

al:

指向尚未初始化的邻接表的指针。

模式:

一个常量,用于指定要在邻接表中包含传出 (IGRAPH_OUT)、传入 (IGRAPH_IN) 或两种类型 (IGRAPH_ALL) 的邻居(在补图中)。 它对于无向网络将被忽略。

循环:

是否考虑循环边。

返回值: 

错误代码。

另请参阅: 

时间复杂度:O(|V|^2+|E|),顶点数量呈二次方。

10.1.4. igraph_adjlist_init_from_inclist — 从关联列表构造顶点邻接表。

igraph_error_t igraph_adjlist_init_from_inclist(
    const igraph_t *graph, igraph_adjlist_t *al, const igraph_inclist_t *il);

在某些算法中,拥有邻接表同一图的关联列表表示形式很有用,并且在许多情况下,如果它们彼此一致,则最有用,即可以保证顶点 v 的邻接列表的第 i 个条目中的顶点 ID 是同一顶点的关联列表的第 i 个条目中边的另一个端点。 此函数通过查找关联列表中每条边的端点并构造相应的邻接向量,从相应的关联列表创建这样的邻接列表。

邻接表在创建后独立于该图或关联列表;换句话说,对图或关联列表所做的修改不会反映在邻接列表中。

参数: 

:

输入图。

al:

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

il:

指向将转换为邻接列表的已初始化 igraph_inclist_t 对象的指针。

返回值: 

错误代码。

时间复杂度:O(|V|+|E|),顶点数和边数的线性关系。

10.1.5. igraph_adjlist_destroy — 释放邻接表的内存。

void igraph_adjlist_destroy(igraph_adjlist_t *al);

释放为邻接表分配的所有内存。

参数: 

al:

要销毁的邻接表。

时间复杂度:取决于内存管理。

10.1.6. igraph_adjlist_get — 查询邻接表中的向量。

#define igraph_adjlist_get(al,no)

返回指向邻接表中的 igraph_vector_int_t 对象的指针。 可以根据需要修改该向量。

参数: 

al:

邻接表对象。

no:

将返回其相邻顶点的顶点。

返回值: 

指向 igraph_vector_int_t 对象的指针。

时间复杂度:O(1)。

10.1.7. igraph_adjlist_size — 返回邻接表中的顶点数。

igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al);

参数: 

al:

邻接表。

返回值: 

邻接表中的顶点数。

时间复杂度:O(1)。

10.1.8. igraph_adjlist_clear — 从邻接表中删除所有边。

void igraph_adjlist_clear(igraph_adjlist_t *al);

参数: 

al:

邻接表。 时间复杂度:取决于内存管理,通常为 O(n),其中 n 是邻接表中元素的总数。

10.1.9. igraph_adjlist_sort — 对邻接表中的每个向量进行排序。

void igraph_adjlist_sort(igraph_adjlist_t *al);

对邻接表的每个向量进行排序。 请注意,igraph_adjlist_init() 已经生成排序的邻居列表。 当邻接表以不同的方式生成或以不保留排序顺序的方式修改时,此函数很有用。

参数: 

al:

邻接表。

时间复杂度:O(n log n),n 是邻接表中元素的总数。

10.1.10. igraph_adjlist_simplify — 简化邻接表。

igraph_error_t igraph_adjlist_simplify(igraph_adjlist_t *al);

简化邻接表,即删除循环边和多条边。

当使用 igraph_adjlist_init() 创建邻接表时,请改为使用该函数的 loopsmultiple 参数。

参数: 

al:

邻接表。

返回值: 

错误代码。

时间复杂度:O(|V|+|E|),在边和顶点的数量上是线性的。

10.2. 关联边

10.2.1. igraph_inclist_init — 初始化关联列表。

igraph_error_t igraph_inclist_init(const igraph_t *graph,
                        igraph_inclist_t *il,
                        igraph_neimode_t mode,
                        igraph_loops_t loops);

创建一个向量列表,其中包含所有顶点的关联边。 关联列表在创建后独立于该图,图对象的后续更改不会更新关联列表,并且对关联列表的更改不会更新该图。

modeIGRAPH_INIGRAPH_OUT 时,每个边 ID 将在关联列表中出现一次。modeIGRAPH_ALL 时,每个边 ID 将在关联列表中出现两次,一次表示源顶点,一次表示目标边。 这也意味着循环边的边 ID 可能会为同一顶点出现两次。使用 loops 参数来控制是否会出现这种情况 (IGRAPH_LOOPS_TWICE) 或不出现 (IGRAPH_LOOPS_ONCEIGRAPH_NO_LOOPS)。

从 igraph 0.10 开始,将 loops 设置为与 IGRAPH_LOOPS_TWICE 不同的值会产生少量性能成本。

参数: 

:

输入图。

il:

指向未初始化的关联列表的指针。

模式:

一个常量,用于指定是否将传入边 (IGRAPH_IN)、传出边 (IGRAPH_OUT) 或两者 (IGRAPH_ALL) 包含在有向图的关联列表中。 它对于无向图将被忽略。

循环:

指定如何处理循环边。 IGRAPH_NO_LOOPS 从关联列表中删除循环边。 IGRAPH_LOOPS_ONCE 使每个循环边仅在相应顶点的关联列表中出现一次。 IGRAPH_LOOPS_TWICE 使循环边在相应顶点的关联列表中出现两次,但仅当图是无向图或 mode 设置为 IGRAPH_ALL 时。

返回值: 

错误代码。

时间复杂度:O(|V|+|E|),顶点数和边数的线性关系。

10.2.2. igraph_inclist_destroy — 释放为关联列表分配的所有内存。

void igraph_inclist_destroy(igraph_inclist_t *il);

参数: 

eal:

要销毁的关联列表。

时间复杂度:取决于内存管理。

10.2.3. igraph_inclist_get — 查询关联列表中的向量。

#define igraph_inclist_get(il,no)

返回指向关联列表中包含边 ID 的 igraph_vector_int_t 对象的指针。 可以根据需要修改、调整大小等向量。

参数: 

il:

指向关联列表的指针。

no:

将为其返回关联边的顶点。

返回值: 

指向 igraph_vector_int_t 对象的指针。

时间复杂度:O(1)。

10.2.4. igraph_inclist_size — 返回关联列表中的顶点数。

igraph_integer_t igraph_inclist_size(const igraph_inclist_t *il);

参数: 

il:

关联列表。

返回值: 

关联列表中的顶点数。

时间复杂度:O(1)。

10.2.5. igraph_inclist_clear — 从关联列表中删除所有边。

void igraph_inclist_clear(igraph_inclist_t *il);

参数: 

il:

关联列表。

时间复杂度:取决于内存管理,通常为 O(n),其中 n 是关联列表中元素的总数。

10.3. 顶点的惰性邻接表

10.3.1. igraph_lazy_adjlist_init — 初始化一个惰性邻接表。

igraph_error_t igraph_lazy_adjlist_init(const igraph_t *graph,
                             igraph_lazy_adjlist_t *al,
                             igraph_neimode_t mode,
                             igraph_loops_t loops,
                             igraph_multiple_t multiple);

为顶点创建一个惰性邻接表。 此函数仅分配一些内存用于存储邻接表的向量,但不会查询相邻顶点,仅在调用 igraph_lazy_adjlist_get() 时才会查询。 邻居列表将按排序顺序返回。

从 igraph 0.10 开始,将 loops 设置为与 IGRAPH_LOOPS_TWICE 不同的值,或者将 multiple 设置为与 IGRAPH_MULTIPLE 不同的值,会产生少量性能成本。

参数: 

:

输入图。

al:

指向未初始化的邻接表对象的指针。

模式:

一个常量,用于指定邻接表中是否只包含传出 (IGRAPH_OUT)、只包含传入 (IGRAPH_IN) 或两种类型 (IGRAPH_ALL) 的邻居。 它对于无向图将被忽略。

循环:

指定如何处理循环边。 IGRAPH_NO_LOOPS 从邻接表中删除循环边。 IGRAPH_LOOPS_ONCE 使每个循环边仅在相应顶点的邻接表中出现一次。 IGRAPH_LOOPS_TWICE 使循环边在相应顶点的邻接表中出现两次,但仅当图是无向图或 mode 设置为 IGRAPH_ALL 时。

multiple:

指定如何处理多(并行)边。 IGRAPH_NO_MULTIPLE 将并行边折叠为单个边;IGRAPH_MULTIPLE 保留并行边的多重性,因此相同的顶点在另一个顶点的邻接表中出现的次数与两个顶点之间边的并行边的数量一样多。

返回值: 

错误代码。

另请参阅: 

用于获取各个顶点的邻居列表的 igraph_neighbors()

时间复杂度:O(|V|),顶点数,可能取决于底层内存管理。

10.3.2. igraph_lazy_adjlist_destroy — 释放一个惰性邻接表。

void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al);

释放为惰性邻接表分配的所有内存。

参数: 

al:

要释放的邻接表。

时间复杂度:取决于内存管理。

10.3.3. igraph_lazy_adjlist_get — 查询相邻顶点。

#define igraph_lazy_adjlist_get(al,no)

如果首次为顶点调用该函数,则结果将存储在邻接列表中,并且在再次查询同一顶点的邻居时,不需要进一步的查询操作。

参数: 

al:

惰性邻接表。

no:

要查询的顶点 ID。

返回值: 

指向向量的指针,或者发生错误时指向 NULL。 仅在首次为给定顶点调用此函数时才会发生错误。 可以安全地修改此向量,修改不会影响原始图。

另请参阅: 

使用 igraph_lazy_adjlist_has() 检查是否已为顶点调用此函数。

时间复杂度:首次为 O(d),顶点数量,后续调用为 O(1)。

10.3.4. igraph_lazy_adjlist_has — 相邻顶点是否已存储在惰性邻接列表中?

#define igraph_lazy_adjlist_has(al,no)

参数: 

al:

惰性邻接表。

no:

要查询的顶点 ID。

返回值: 

如果已计算并存储此顶点的相邻顶点,则为 True,否则为 false。

时间复杂度:O(1)。

10.3.5. igraph_lazy_adjlist_size — 返回惰性邻接表中的顶点数。

igraph_integer_t igraph_lazy_adjlist_size(const igraph_lazy_adjlist_t *al);

参数: 

al:

惰性邻接表。

返回值: 

惰性邻接表中的顶点数。

时间复杂度:O(1)。

10.3.6. igraph_lazy_adjlist_clear — 从惰性邻接表中删除所有边。

void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al);

参数: 

al:

惰性邻接表。 时间复杂度:取决于内存管理,通常为 O(n),其中 n 是邻接表中元素的总数。

10.4. 边的惰性关联列表

10.4.1. igraph_lazy_inclist_init — 初始化边的惰性关联列表。

igraph_error_t igraph_lazy_inclist_init(const igraph_t *graph,
                             igraph_lazy_inclist_t *il,
                             igraph_neimode_t mode,
                             igraph_loops_t loops);

为边创建一个惰性关联列表。 此函数仅分配一些内存用于存储关联列表的向量,但不会查询关联边,仅在调用 igraph_lazy_inclist_get() 时才会查询。

modeIGRAPH_INIGRAPH_OUT 时,每个边 ID 将在关联列表中出现一次。modeIGRAPH_ALL 时,每个边 ID 将在关联列表中出现两次,一次表示源顶点,一次表示目标边。 这也意味着循环边的边 ID 将为同一顶点出现两次。

从 igraph 0.10 开始,将 loops 设置为与 IGRAPH_LOOPS_TWICE 不同的值会产生少量性能成本。

参数: 

:

输入图。

al:

指向未初始化的关联列表的指针。

模式:

一个常量,用于指定是否考虑传入边 (IGRAPH_IN)、传出边 (IGRAPH_OUT) 或两种类型的边 (IGRAPH_ALL)。 它对于无向图将被忽略。

循环:

指定如何处理循环边。 IGRAPH_NO_LOOPS 从关联列表中删除循环边。 IGRAPH_LOOPS_ONCE 使每个循环边仅在相应顶点的关联列表中出现一次。 IGRAPH_LOOPS_TWICE 使循环边在相应顶点的关联列表中出现两次,但仅当图是无向图或 mode 设置为 IGRAPH_ALL 时。

返回值: 

错误代码。

时间复杂度:O(|V|),顶点数,可能。 但这也取决于底层内存管理。

10.4.2. igraph_lazy_inclist_destroy — 释放惰性关联列表。

void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il);

释放为惰性关联列表分配的所有内存。

参数: 

al:

要释放的关联列表。

时间复杂度:取决于内存管理。

10.4.3. igraph_lazy_inclist_get — 查询关联边。

#define igraph_lazy_inclist_get(il,no)

如果该函数是第一次为一个顶点调用,则结果存储在关联列表中,当再次查询同一顶点的关联边时,不需要进一步的查询操作。

参数: 

il:

惰性关联列表对象。

no:

要查询的顶点 ID。

返回值: 

指向向量的指针,或者发生错误时指向 NULL。 仅在首次为给定顶点调用此函数时才会发生错误。 可以安全地修改此向量,修改不会影响原始图。

另请参阅: 

igraph_lazy_inclist_has() 用于检查此函数是否已被某个顶点调用过。

时间复杂度:O(d),首次调用时为关联边的数量,对于使用相同 no 参数的后续调用,时间复杂度为 O(1)。

10.4.4. igraph_lazy_inclist_has — 关联边是否已存储在惰性关联列表中?

#define igraph_lazy_inclist_has(il,no)

参数: 

il:

惰性关联列表。

no:

要查询的顶点 ID。

返回值: 

如果该顶点的关联边已被计算并存储,则为 True;否则为 false。

时间复杂度:O(1)。

10.4.5. igraph_lazy_inclist_size — 返回惰性关联列表中的顶点数。

igraph_integer_t igraph_lazy_inclist_size(const igraph_lazy_inclist_t *il);

参数: 

il:

惰性关联列表。

返回值: 

惰性关联列表中的顶点数。

时间复杂度:O(1)。

10.4.6. igraph_lazy_inclist_clear — 从惰性关联列表中移除所有边。

void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il);

参数: 

il:

惰性关联列表。

时间复杂度:取决于内存管理,通常为 O(n),其中 n 是关联列表中元素的总数。

11. 部分前缀和树

igraph_psumtree_t 数据类型表示部分前缀和树。 部分前缀和树是一种数据结构,可用于从动态概率的离散概率分布中抽取样本,这些概率会频繁更新。 这是通过创建一个二叉树来实现的,其中叶子是各项。 每个叶子包含与该项对应的概率。 树的中间节点始终包含其两个子节点的总和。 当叶节点的值更新时,其祖先的值也会相应更新。

可以通过生成 0(包括)到树的根的值(不包括)之间的均匀随机数,然后按照以下步骤沿着树的分支进行,从而从树表示的概率分布中抽取样本。 在每个步骤中,将当前节点中的值与生成的数字进行比较。 如果节点中的值较大,则采用树的左分支;否则,生成的数字减去节点中的值,然后采用树的右分支,直到到达叶节点。

请注意,仅当树中的所有值均为非负数时,采样过程才有效。 这是由对象强制执行的;特别是,尝试为某一项设置负值会产生 igraph 错误。

11.1. igraph_psumtree_init — 初始化部分前缀和树。

igraph_error_t igraph_psumtree_init(igraph_psumtree_t *t, igraph_integer_t size);

树使用固定数量的元素进行初始化。 初始化后,与每个元素对应的值均为零。

参数: 

t:

要初始化的树。

大小:

树中的元素数。 必须至少为一。

返回值: 

错误代码,如果没有足够的内存,通常为 IGRAPH_ENOMEM

时间复杂度:对于包含 n 个元素的树,时间复杂度为 O(n)

11.2. igraph_psumtree_destroy — 销毁部分前缀和树。

void igraph_psumtree_destroy(igraph_psumtree_t *t);

igraph_psumtree_init() 初始化的所有部分前缀和树都应通过此函数正确销毁。 如果要再次使用已销毁的树,则需要通过 igraph_psumtree_init() 重新初始化。

参数: 

t:

指向要销毁的(先前已初始化)树的指针。

时间复杂度:操作系统相关。

11.3. igraph_psumtree_size — 返回树的大小。

igraph_integer_t igraph_psumtree_size(const igraph_psumtree_t *t);

参数: 

t:

树对象

返回值: 

树中的离散项的数量。

时间复杂度:O(1)。

11.4. igraph_psumtree_get — 检索树中与某个项对应的值。

igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, igraph_integer_t idx);

参数: 

t:

要查询的树。

idx:

要检索其值的项的索引。

返回值: 

与给定索引的项对应的值。

时间复杂度:O(1)

11.5. igraph_psumtree_sum — 返回树中叶子的值的总和。

igraph_real_t igraph_psumtree_sum(const igraph_psumtree_t *t);

参数: 

t:

树对象

返回值: 

树中叶子的值的总和。

时间复杂度:O(1)。

11.6. igraph_psumtree_search — 给定一个值,在树中查找一个项。

igraph_error_t igraph_psumtree_search(const igraph_psumtree_t *t, igraph_integer_t *idx,
                           igraph_real_t search);

此函数查找具有最低索引的项,在该项中,所有索引较低的项的总和小于或等于给定值,并且所有索引较低的项的总和加上该项本身大于给定值。

如果您将部分前缀和树视为从离散概率分布中采样的工具,那么重复调用此函数,并将 0(包括)到树中所有值的总和(不包括)范围内的均匀分布的随机数作为参数,将以与其关联值成比例的概率对树中的项进行采样。

参数: 

t:

要查询的树。

idx:

此处返回项的索引。

search:

用于搜索的值。 必须在区间 [0, sum) 内,其中 sum 是树中所有元素(叶子)的总和。

返回值: 

错误代码;当前搜索始终成功。

时间复杂度:O(log n),其中 n 是树中项的数量。

11.7. igraph_psumtree_update — 更新树中与某个项关联的值。

igraph_error_t igraph_psumtree_update(igraph_psumtree_t *t, igraph_integer_t idx,
                           igraph_real_t new_value);

参数: 

t:

要查询的树。

idx:

要更新的项的索引。

new_value:

项的新值。

返回值: 

错误代码,如果新值为负数或 NaN,则为 IGRAPH_EINVAL;如果操作成功,则为 IGRAPH_SUCCESS

时间复杂度:O(log n),其中 n 是树中项的数量。

11.8. igraph_psumtree_reset — 将树中的所有值重置为零。

void igraph_psumtree_reset(igraph_psumtree_t *t);

参数: 

t:

要重置的树。

12. 位集

12.1.  关于 igraph_bitset_t 对象

igraph_bitset_t 数据类型是包含布尔值的数组的简单而有效的接口。 它类似于 C++ 标准库中的 bitset 模板,尽管主要区别在于 C++ 版本的位集大小在编译时初始化。

igraph_bitset_t 类型使用 O(n/w) 空间来存储 n 个元素,其中 w 是 igraph_integer_t 的位宽,igraph_integer_t 是整个库中使用的整数类型(32 或 64)。 有时它们会使用更多空间,这是因为位集可以缩小,但即使它们缩小,当前的实现也不会释放任何内存。

igraph_bitset_t 对象及其变体中的元素从零开始索引,我们在此遵循通常的 C 约定。 位集从右到左索引,这意味着索引 0 是最低有效位,索引 n - 1 是最高有效位。

位集的元素始终占用单个内存块,可以使用 VECTOR() 宏查询此内存块的起始地址。 这样,位集对象可以与标准数学库(如 GNU 科学库)一起使用。

请注意,虽然位集函数的接口类似于 igraph 的向量函数,但有一个主要区别:位集函数(例如 igraph_bitset_and())不会验证输入参数的大小是否兼容,也不会自动调整输出参数的大小。 这样做是用户的责任。

12.2.  构造函数和析构函数

igraph_bitset_t 对象在使用之前必须初始化,这类似于对它们调用构造函数。 为了您的方便,有两种 igraph_bitset_t 构造函数。 igraph_bitset_init() 是基本构造函数,它创建一个给定长度的位集,并用零填充。 igraph_bitset_init_copy() 创建一个已存在并已初始化的位集的新相同副本。

如果不再需要 igraph_bitset_t 对象,则应通过调用 igraph_bitset_t 析构函数 igraph_bitset_destroy() 来销毁它以释放其分配的内存。

12.2.1. igraph_bitset_init — 初始化位集对象(构造函数)。

igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

每个位集在使用之前都需要初始化,并且有许多初始化函数或以其他方式调用的构造函数。 此函数构造一个给定大小的位集,并将每个条目初始化为 0。

由该函数初始化的每个位集对象都应在不再需要时销毁(即,为其分配的内存应释放),igraph_bitset_destroy() 函数负责此操作。

参数: 

bitset:

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

大小:

位集的大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,分配 O(n/w) 个元素所需的时间量,n 是元素的数量。 w 是机器的字大小(32 或 64)。

12.2.2. igraph_bitset_init_copy — 从另一个位集对象初始化位集(构造函数)。

igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitset_t *src);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

现有位集对象的内容将被复制到新的位集对象中。

参数: 

dest:

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

src:

要复制的原始位集对象。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,通常为 O(n/w),n 是位集的大小,w 是机器的字大小(32 或 64)。

12.2.3. igraph_bitset_destroy — 销毁位集对象。

void igraph_bitset_destroy(igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

igraph_bitset_init() 初始化的所有位集都应通过此函数正确销毁。 销毁的位集需要通过 igraph_bitset_init() 或另一个构造函数重新初始化。

参数: 

bitset:

指向要销毁的(先前已初始化的)位集对象的指针。

时间复杂度:操作系统相关。

12.3.  访问元素

访问位集元素的***简单方法是使用 IGRAPH_BIT_TEST()IGRAPH_BIT_SET()IGRAPH_BIT_CLEAR() 宏。

还有一些其他宏允许手动操作位集。 这些宏是 VECTOR()IGRAPH_BIT_SLOT()IGRAPH_BIT_MASK()IGRAPH_BIT_NSLOTS()

12.3.1. IGRAPH_BIT_MASK — 计算用于访问整数特定位的掩码。

#define IGRAPH_BIT_MASK(i)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

IGRAPH_BIT_SLOT() 结合使用以访问位集的元素。 用法

 IGRAPH_BIT_MASK(10) 

获得一个整数,其中仅设置了第 11 个最低有效位。 请注意,在此处传递负值会导致未定义的行为。

参数: 

b:

唯一应设置其位的位索引。

时间复杂度:O(1)。

12.3.2. IGRAPH_BIT_SLOT — 计算用于访问位集特定槽的索引。

#define IGRAPH_BIT_SLOT(i)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

IGRAPH_BIT_MASK 结合使用以访问位集的元素。 用法

 IGRAPH_BIT_SLOT(70) 

如果使用 64 位字,将返回 1;如果使用 32 位字,将返回 2。

参数: 

i:

应确定其槽的位索引。

时间复杂度:O(1)。

12.3.3. IGRAPH_BIT_SET — 将位集中特定位设置为 1,而不更改其他位。

#define IGRAPH_BIT_SET(bitset, i)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

用法

 IGRAPH_BIT_SET(bitset, 3) 

会将位集中第四个最低有效位设置为 1。

参数: 

bitset:

位集

i:

应将其位在操作后设置为 1 的位索引。

时间复杂度:O(1)。

12.3.4. IGRAPH_BIT_CLEAR — 将位集中特定位设置为 0,而不更改其他位。

#define IGRAPH_BIT_CLEAR(bitset, i)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

用法

 IGRAPH_BIT_CLEAR(bitset, 4) 

会将位集中第五个最低有效位设置为 0。

参数: 

bitset:

位集

i:

应将其位在操作后设置为 0 的位索引。

时间复杂度:O(1)。

12.3.5. IGRAPH_BIT_TEST — 测试位集中是否已设置某位。

#define IGRAPH_BIT_TEST(bitset, i)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

如果未设置指定位索引处的位,则返回 0;否则返回非零值。 用法

 IGRAPH_BIT_TEST(bitset, 7) 

将测试位集中第八个最低有效位。

参数: 

bitset:

位集

i:

应测试其位的位索引。

时间复杂度:O(1)。

12.3.6. IGRAPH_BIT_NSLOTS — 计算存储指定数量位所需的槽数。

#define IGRAPH_BIT_NSLOTS(nbits)

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

用法

 IGRAPH_BIT_NSLOTS(70) 

如果使用 64 位字,将返回 2;如果使用 32 位字,将返回 3。

 IGRAPH_BIT_NSLOTS(128) 

如果使用 64 位字,将返回 2;如果使用 32 位字,将返回 4。

参数: 

nbits:

指定的位数。

时间复杂度:O(1)。

12.4. 位集操作

12.4.1. igraph_bitset_fill — 使用常量值填充位集。

void igraph_bitset_fill(igraph_bitset_t *bitset, igraph_bool_t value);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

将位集的所有位设置为相同的值。

参数: 

bitset:

要修改的位集对象。

:

要为所有位设置的值。

另请参阅: 

时间复杂度:O(n/w)。

12.4.2. igraph_bitset_null — 清除位集中的所有位。

void igraph_bitset_null(igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

要在其中清除所有位的位集对象。

另请参阅: 

时间复杂度:O(n/w)。

12.4.3. igraph_bitset_or — 两个位集的按位或。

void igraph_bitset_or(igraph_bitset_t *dest,
                      const igraph_bitset_t *src1, const igraph_bitset_t *src2);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

将按位或应用于两个位集的内容,并将其存储在已初始化的位集中。 目标位集可能等于一个(甚至两个)源位集。 使用位集时,通常创建的位集是大小固定的相同大小。 因此,此函数不检查传递给它的位集的大小,如有必要,调用方必须这样做。

参数: 

dest:

存储结果的位集对象

src1:

位集。 必须具有与 dest 相同的大小。

src2:

位集。 必须具有与 dest 相同的大小。

时间复杂度:O(n/w)。

12.4.4. igraph_bitset_and — 两个位集的按位与。

void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const igraph_bitset_t *src2);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

将按位与应用于两个位集的内容,并将其存储在已初始化的位集中。 目标位集可能等于一个(甚至两个)源位集。 使用位集时,通常创建的位集是大小固定的相同大小。 因此,此函数不检查传递给它的位集的大小,如有必要,调用方必须这样做。

参数: 

dest:

存储结果的位集对象

src1:

位集。 必须具有与 dest 相同的大小。

src2:

位集。 必须具有与 dest 相同的大小。

时间复杂度:O(n/w)。

12.4.5. igraph_bitset_xor — 两个位集的按位异或。

void igraph_bitset_xor(igraph_bitset_t *dest,
                       const igraph_bitset_t *src1, const igraph_bitset_t *src2);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

将按位异或应用于两个位集的内容,并将其存储在已初始化的位集中。 目标位集可能等于一个(甚至两个)源位集。 使用位集时,通常创建的位集是大小固定的相同大小。 因此,此函数不检查传递给它的位集的大小,如有必要,调用方必须这样做。

参数: 

dest:

存储结果的位集对象

src1:

位集。 必须具有与 dest 相同的大小。

src2:

位集。 必须具有与 dest 相同的大小。

时间复杂度:O(n/w)。

12.4.6. igraph_bitset_not — 位集的按位取反。

void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

将按位非应用于位集的内容,并将其存储在已初始化的位集中。 目标位集可能等于源位集。 使用位集时,通常创建的位集是大小固定的相同大小。 因此,此函数不检查传递给它的位集的大小,如有必要,调用方必须这样做。

参数: 

dest:

存储结果的位集对象

src:

位集。 必须具有与 dest 相同的大小。

时间复杂度:O(n/w)。

12.4.7. igraph_bitset_popcount — 位集的总体计数。

igraph_integer_t igraph_bitset_popcount(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

返回位集中已设置位的数量,也称为总体计数。

参数: 

bitset:

位集对象

返回值: 

位集的总体计数。

时间复杂度:O(n/w)。

12.4.8. igraph_bitset_countl_zero — 位集中前导零的数量。

igraph_integer_t igraph_bitset_countl_zero(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

返回位集中第一个一之前的前导(从最高有效位开始)零的数量。 如果位集全为零,则返回其大小。

参数: 

bitset:

位集对象

返回值: 

位集中前导零的数量。

时间复杂度:O(n/w)。

12.4.9. igraph_bitset_countl_one — 位集中前导一的数量。

igraph_integer_t igraph_bitset_countl_one(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

返回位集中第一个零之前的前导(从最高有效位开始)一的数量。 如果位集全为一,则返回其大小。

参数: 

bitset:

位集对象

返回值: 

位集中前导一的数量。

时间复杂度:O(n/w)。

12.4.10. igraph_bitset_countr_zero — 位集中尾随零的数量。

igraph_integer_t igraph_bitset_countr_zero(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

返回位集中第一个一之前的尾随(从最低有效位开始)零的数量。 如果位集全为零,则返回其大小。

参数: 

bitset:

位集对象

返回值: 

位集中尾随零的数量。

时间复杂度:O(n/w)。

12.4.11. igraph_bitset_countr_one — 位集中尾随一的数量。

igraph_integer_t igraph_bitset_countr_one(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

返回位集中第一个零之前的尾随(从最低有效位开始)一的数量。 如果位集全为一,则返回其大小。

参数: 

bitset:

位集对象

返回值: 

位集中尾随一的数量。

时间复杂度:O(n/w)。

12.4.12. igraph_bitset_is_all_zero — 所有位是否均为零?

igraph_bool_t igraph_bitset_is_all_zero(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

要测试的位集对象。

返回值: 

如果未设置任何位,则为 True。

时间复杂度:O(n/w)。

12.4.13. igraph_bitset_is_all_one — 所有位是否均为一?

igraph_bool_t igraph_bitset_is_all_one(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

要测试的位集对象。

返回值: 

如果所有位均已设置,则为 True。

时间复杂度:O(n/w)。

12.4.14. igraph_bitset_is_any_zero — 是否有任何位为零?

igraph_bool_t igraph_bitset_is_any_zero(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

要测试的位集对象。

返回值: 

如果至少有一位为零,则为 True。

时间复杂度:O(n/w)。

12.4.15. igraph_bitset_is_any_one — 是否有任何位为一?

igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

要测试的位集对象。

返回值: 

如果至少有一位为一,则为 True。

时间复杂度:O(n/w)。

12.5. 位集属性

12.5.1. igraph_bitset_size — 返回位集的长度。

igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

参数: 

bitset:

位集对象

返回值: 

位集的大小。

时间复杂度:O(1)。

12.5.2. igraph_bitset_capacity — 返回位集的已分配容量。

igraph_integer_t igraph_bitset_capacity(const igraph_bitset_t *bitset);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

请注意,这可能与位集的大小(由 igraph_bitset_size() 查询)不同,并指定位集可以在不重新分配的情况下容纳多少个元素。

参数: 

bitset:

指向要查询的(先前已初始化的)位集对象的指针。

返回值: 

已分配容量。

另请参阅: 

时间复杂度:O(1)。

12.6. 调整大小操作

12.6.1. igraph_bitset_reserve — 为位集预留内存。

igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t capacity);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

igraph 位集是灵活的,它们可以增长和缩小。 但是,增长偶尔需要复制位集中的数据。 为了避免这种情况,您可以调用此函数来为位集的未来增长预留空间。

请注意,此函数不会更改位集的大小。 让我们看一个小例子来澄清一下:如果您为 100 个元素预留空间,并且您的位集的大小是(并且仍然是)60,那么您肯定可以在位集被复制之前向其添加额外的 40 个元素。

参数: 

bitset:

位集对象。

capacity:

位集的新的已分配大小。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,应在 O(n/w) 附近,n 是位集的新分配大小,w 是机器的字大小(32 或 64)。

12.6.2. igraph_bitset_resize — 调整位集的大小。

igraph_error_t igraph_bitset_resize(igraph_bitset_t *bitset, igraph_integer_t new_size);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

请注意,此函数不会释放任何内存,只会将位集的大小设置为给定的大小。 另一方面,如果新大小大于先前的大小,它可能会分配更多内存。 在这种情况下,位集中新出现的元素将设置为零。

参数: 

bitset:

位集对象

new_size:

位集的新大小。

返回值: 

错误代码,如果没有足够的内存,则为 IGRAPH_ENOMEM。 请注意,如果位集变小,此函数从不返回错误。

另请参阅: 

请参阅 igraph_bitset_reserve(),了解为位集的未来扩展分配内存的信息。

时间复杂度:如果新大小较小,则为 O(1);如果新大小较大,则取决于操作系统。 在后一种情况下,它通常在 O(n/w) 附近,n 是位集的新大小,w 是机器的字大小(32 或 64)。

12.7. 复制位集

12.7.1. igraph_bitset_update — 从另一个位集更新位集。

igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src);

警告

此函数是实验性的,其签名尚未被视为最终签名。我们保留更改函数签名的权利,而无需更改 igraph 的主要版本。使用它需要您自担风险。

dest 的大小和内容将与 src 的大小和内容相同。

参数: 

dest:

指向已初始化的位集对象的指针。 这将被更新。

src:

要从中更新的位集。

返回值: 

错误代码:如果没有足够的内存,则为 IGRAPH_ENOMEM

时间复杂度:取决于操作系统,通常为 O(n/w),n 是位集的大小,w 是机器的字大小(32 或 64)。