【发布时间】:2017-08-28 08:14:55
【问题描述】:
好吧,我正在制作一个 c++ 程序,它会处理很长的符号流,我需要存储信息以供进一步分析,流中出现特定长度的符号序列。例如在二进制流中
100110010101
我有一个长度为 6 的序列,例如:
- 100110 从位置 0 开始
- 001100 从位置 1 开始
- 011001 从位置 2 开始
- 等
我需要存储的是可以找到一个特定序列的所有位置的向量。所以结果应该是一个表格,可能类似于一个哈希表,如下所示:
顺序/位置
10010101 | 1 13 147 515
01011011 | 67 212 314 571
00101010 | 2 32 148 322 384 419 455
等等。
现在,我发现将字符串映射到整数很慢,所以因为我在流中预先掌握了有关符号的信息,所以我可以使用它将这个固定长度的序列映射到整数。
下一步是创建一个映射,将这些“代表整数”映射到表中的相应索引,我在其中添加该序列的下一次出现。然而,这很慢,比我能承受的要慢得多。我尝试了 std 和 boost 库的有序和无序映射,没有一个有足够的效率。我测试了一下,地图才是这里真正的瓶颈
这是伪代码中的循环:
for (int i=seqleng-1;i<stream.size();i++) {
//compute characteristic value for the sequence by adding one symbol
charval*=symb_count;
charval+=sdata[j][i]-'0';
//sampspacesize is number off all possible sequence with this symbol count and this length
charval%=sampspacesize;
map<uint64,uint64>::iterator &it=map.find(charval);
//if index exists, add starting position of the sequence to the table
if (it!=map.end()) {
(table[it->second].add(i-seqleng+1);
}
//if current sequence is found for the first time, extend the table and add the index
else {
table.add_row();
map[charval]=table.last_index;
table[table.last_index].add(i-seqleng+1)
}
}
所以问题是,我可以使用比地图更好的东西来记录表中相应的索引,还是这是最好的方法?
注意:我知道这里有一种快速的方法,那就是为每个可能的符号序列创建足够大的存储空间(这意味着如果我有长度为 10 和 4 个符号的序列,我会保留 4^10 个插槽并且可以省略映射),但我将需要处理符号的长度和数量,这会导致保留的内存量超出计算机的容量。但是实际使用的slot数不会超过1亿(这是由最大流长度保证的),并且可以存储在计算机中。
如果有什么不清楚的地方,请提出任何问题,这是我在这里的第一个大问题,所以我缺乏经验来表达自己的其他人会理解的方式。
【问题讨论】:
-
您要将序列映射到位置,还是将位置映射到序列?
-
@RichardHodges 数字分为三种,一种是表示序列的数字,一种是表中的索引,一种是位置。我想将代表序列的数字映射到表中的索引(在这个索引下是这个序列的位置)。
-
看来你有
std::map<sequence, tableIndex> map和MyVector<MyVector<Position>>。为什么不直接std::map<sequence, std::vector<Position>> map? -
@Jarod42 它更慢了。地图中的结构越复杂,加载循环越慢。我一路下降到一次只加载一个符号并将整数映射到整数,但是从这里我无法提高速度,因为这些是最简单的数据类型,除了使用我的 map 之外别无他法知道。
-
如果您只使用符号
1和0,那么为什么不将其存储为unordered_map,例如uint_8t,其中您的密钥是数字 对应你的二进制展开?读取源字符串时,您只需要逐个字符地读取,边走边写。
标签: c++ optimization micro-optimization