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
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::set
和RleVec::insert
需要T: Clone
。
Vec
上实现的所有方法并未在RleVec
上实现。所有返回切片的方法都无法在RleVec
上工作。
序列化
支持序列化的Serde
作为cargo功能可用。您可以在Cargo.toml
的dependencies
部分指定功能。
[dependencies]
rle_vec = { version = "0.4.0", features = ["serialize"] }
预期用途
- 在假设数据将保持稀疏的情况下,使用起始值分配巨大的向量,并(随机)更新位置。更新步骤将比使用
Vec
慢。 - 显然,当
RleVec<T>
中的T
大小很大时,节省更大。 - 如果你想在序列化之前减少内存中的结构。
基准测试
可以使用 Cargo bench
来比较 Vec
和 RleVec
上获取/设置/插入/删除操作的实际差异。警告,一些测试涉及重新分配。
创建
除非数据非常稀疏,否则从切片创建似乎是最快的。
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