#rle #vec #vector

rle_vec

类似于向量结构的类型,将数据存储为相同值的序列。适用于存储稀疏数据。

8个版本

使用旧的Rust 2015

0.4.1 2021年2月19日
0.4.0 2018年9月26日
0.3.1 2017年10月27日
0.2.2 2017年2月1日
0.1.0 2016年11月28日

#719数据结构

26 每月下载次数
用于 rezcraft

MIT 许可证

51KB
731

RleVec

一个Rust包,提供了一个类似于向量结构的类型,该类型将数据存储为相同值的序列。

如果你的数据由一段段相同的值组成,那么只存储每个值出现的次数可能会有所帮助。这可以显著节省空间,但代价是访问任意索引需要遍历存储的序列,导致时间复杂度为(log n),与普通向量的O(1)相比有所增加。其他复杂度在表中,其中n等于序列的数量,而不是可比较的Vec的长度。

push 索引 设置时会中断序列 设置时不会中断序列 插入时会中断序列 插入时不会中断序列
RleVec O(1) O(log n) O((log n) + 2n) O(log n) O((log n) + 2n) O((log n) + n)
Vec O(1) O(1) O(1)* O(n)

RleVec结构类似于普通向量,并支持Vec方法的一个子集。

用法

将此放在你的Cargo.toml

[dependencies]
rle_vec = "0.4"

并在你的包根目录下

extern crate rle_vec;

示例

use rle_vec::RleVec;

let mut rle = RleVec::new();

rle.push(10);
rle.push(10);
rle.push(11);
assert_eq!(rle[1], 10);
assert_eq!(rle[2], 11);

rle.insert(1, 10);
assert_eq!(rle.runs_len(), 2);

rle.set(0, 10);
assert_eq!(rle.runs_len(), 3);

RleVec可以从Iterators构建,并像Vec一样迭代。

use rle_vec::RleVec;

let v = vec![0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 4, 5, 4, 4, 4];

let mut rle: RleVec<_> = v.into_iter().collect();
assert_eq!(rle.len(), 15);
assert_eq!(rle.runs_len(), 7);

assert_eq!(rle.iter().nth(10), Some(&4));

你可以获取索引处的值。

use rle_vec::RleVec;

let v = vec![0, 0, 0, 1, 1, 1, 1, 2, 2, 3];
let mut rle: RleVec<_> = v.into_iter().collect();

rle.set(1, 2);
rle.insert(4, 4);

let v = rle.iter().cloned().collect::<Vec<_>>();
assert_eq!(v, vec![0, 2, 0, 1, 4, 1, 1, 1, 2, 2, 3]);

RleVec::setRleVec::insert需要T: Clone

Vec上实现的所有方法并未在RleVec上实现。所有返回切片的方法都无法在RleVec上工作。

序列化

支持序列化的Serde作为cargo功能可用。您可以在Cargo.tomldependencies部分指定功能。

[dependencies]
rle_vec = { version = "0.4.0", features = ["serialize"] }

预期用途

  • 在假设数据将保持稀疏的情况下,使用起始值分配巨大的向量,并(随机)更新位置。更新步骤将比使用 Vec 慢。
  • 显然,当 RleVec<T> 中的 T 大小很大时,节省更大。
  • 如果你想在序列化之前减少内存中的结构。

基准测试

可以使用 Cargo bench 来比较 VecRleVec 上获取/设置/插入/删除操作的实际差异。警告,一些测试涉及重新分配。

创建

除非数据非常稀疏,否则从切片创建似乎是最快的。

rle_create_1000_runs_of_10_values_from_iter  ... bench:      19,561 ns/iter (+/- 342)
vec_create_1000_runs_of_10_values_from_iter  ... bench:      22,221 ns/iter (+/- 582)

rle_create_1000_runs_of_10_values_from_slice ... bench:       6,076 ns/iter (+/- 324)
vec_create_1000_runs_of_10_values_from_slice ... bench:         894 ns/iter (+/- 45)

rle_create_10_000_equal_values_from_iter     ... bench:          15 ns/iter (+/- 1)
vec_create_10_000_equal_values_from_iter     ... bench:       7,683 ns/iter (+/- 547)

rle_create_10_000_equal_values_from_slice    ... bench:       4,490 ns/iter (+/- 57)
vec_create_10_000_equal_values_from_slice    ... bench:         898 ns/iter (+/- 48)

rle_create_10_000_unique_values_from_iter    ... bench:      25,510 ns/iter (+/- 789)
vec_create_10_000_unique_values_from_slice   ... bench:         891 ns/iter (+/- 47)

rle_create_10_000_unique_values_from_slice   ... bench:      25,936 ns/iter (+/- 278)
vec_create_10_000_unique_values_from_iter    ... bench:         921 ns/iter (+/- 25)

访问

随机访问会受到二分搜索惩罚,但迭代表现合理。

rle_iterate_1000_runs_of_10_values       ... bench:      19,773 ns/iter (+/- 481)
vec_iterate_1000_runs_of_10_values       ... bench:       4,981 ns/iter (+/- 2,171)

rle_iterate_10_000_equal_values          ... bench:      20,878 ns/iter (+/- 538)
vec_iterate_10_000_equal_values          ... bench:       5,149 ns/iter (+/- 124)

rle_iterate_10_000_unique_values         ... bench:      20,130 ns/iter (+/- 340)
vec_iterate_10_000_unique_values         ... bench:       7,784 ns/iter (+/- 127)

rle_random_access_1000_runs_of_10_values ... bench:      34,999 ns/iter (+/- 632)
vec_random_access_1000_runs_of_10_values ... bench:         499 ns/iter (+/- 11)

插入

插入数据具有竞争力,如果不需要运行中断,则可能更快。

rle_insert_runmids_breaking_1000_runs_of_10_values     ... bench:     308,797 ns/iter (+/- 23,860)
rle_insert_runmids_non_breaking_1000_runs_of_10_values ... bench:     171,507 ns/iter (+/- 2,669)
vec_insert_runmids_1000_runs_of_10_values              ... bench:     191,124 ns/iter (+/- 5,439)

设置

可变索引可能会有非常不同的结果。最小成本是二分搜索,但根据插入值,Runs 可以合并或拆分。

test rle_set_runmids_breaking_1000_runs_of_10_values     ... bench:     177,418 ns/iter (+/- 2,718)
test rle_set_runmids_non_breaking_1000_runs_of_10_values ... bench:      34,844 ns/iter (+/- 528)
test rle_set_runs_merging_1000_runs                      ... bench:      97,703 ns/iter (+/- 1,521)
test vec_set_runmids_1000_runs_of_10_values              ... bench:         908 ns/iter (+/- 11)
test vec_set_runs_merging_1000_runs                      ... bench:         785 ns/iter (+/- 27)

删除

删除值可能会有非常不同的结果。最小成本是二分搜索,但根据删除值,Runs 可以合并或拆分。但删除对于 Vec 来说也更昂贵。

test rle_remove_runmids_non_breaking_1000_runs_of_10_values ... bench:     184,023 ns/iter (+/- 5,367)
test rle_remove_runs_merging_1000_runs                      ... bench:     182,233 ns/iter (+/- 5,122)
test vec_remove_runmids_1000_runs_of_10_values              ... bench:     270,981 ns/iter (+/- 6,258)
test vec_remove_runs_merging_1000_runs                      ... bench:      66,948 ns/iter (+/- 1,460)

依赖关系

~185KB